通過反彙編來理解restrict關鍵字

2021-02-19 CPP開發者

(給CPP開發者加星標,提升C/C++技能)

https://blog.csdn.net/songguangfan/article/details/108309181

一次難忘的面試經歷

多年前,一次網際網路某廠實習生的面試題,題目的代碼片段很簡單,如下:

 1  #include <stdlb.h>
  
 2  int main()
 3 {
 4      int *restrict pInt = (int*)malloc(4);
 5      int *pNewInt = pInt;
 6      return 0;
 7 }
12345678


面試官問我運行結果是什麼,我居然當時不加思索的回答,編譯器會報錯。當時個人理解是這樣的,首先用malloc函數分配了一個4Bytes大小的內存,並讓pInt指針指向它。同時pInt指針,也被restrict關鍵字修飾。而restrict就是用來表明是訪問一個數據對象的唯一且初始的方式。因此在第5行中,將pInt的值賦值給了另一個指針pNewInt就是錯誤的。但是遺憾的是,這種錯誤編譯器是不會報錯的。下面我們就這個問題來聊一聊restrict關鍵字。

不使用restrict關鍵字

restrict關鍵字實際上在C99標準出來以前,編譯器就已經開始支持類似restrict的語句了,如編譯器定義了__restrict。restrict關鍵字,實際上是用來指示編譯器對代碼進行優化的。在分析具體含義以前,我們先來看一個沒有用restrict的例子。



在main函數中定義了三個參數p、q、r。這之後調用了f函數,並把p和q的地址傳遞進去。在f中根據這兩個地址,將p和q分別設置為2和3,最後把p的值2當做函數返回值返回,並賦值給整形變量r。這個代碼很簡單,不過重點不是看它,而是它的反彙編代碼,下面我們通過objdump工具執行objdump -j .text -l -C -S test來生成彙編代碼。 首先來看下main函數的彙編代碼。如下圖所示


在反彙編代碼中的可以看到,分別將p和q的地址分別賦值給了rdi和 rsi寄存器。即rdi保存了p的地址,rsi保存了q的地址。之後調用了f函數。而在f函數的反彙編代碼中,通過如下圖所示能確認rdi確實保存著p的地址



 接著,如下圖所示,可以看到通過調用了puts函數向屏幕列印信息



最後,f函數最後用rax所指向區域的值,賦給了eax寄存器,即將p的值放入eax作為返回值返回。


好了,現在有一個疑問,代碼其對應的反彙編代碼幹嘛不直接把立即數2直接賦值給eax,反而多此一舉從rax所指向的內存中把2取出來給eax呢?因為編譯器之所以不直接把2賦值給eax,而非要從內存中獲取,就是擔心代碼中會通過其他指針訪問p所佔的區域。在test.c的代碼中我們通過指針a訪問了p所佔的區域,但是編譯器不知道指針b是否也是指向p所佔的區域,通過指針b是否也對該區域做了修改。因此編譯器只能根據return *a,從內存中將2取出來賦值給eax。

使用restrict關鍵字

好了,怎麼樣才能讓編譯器變得聰明一點呢?這個時候restrict就派上用場了。修改上面代碼



 運行編譯命令gcc -g -O2 -std=c99 -o test test.c進行編譯,使用反彙編工具objdump查看發現


可以看到直接把2賦給了eax寄存器,作為f的返回值返回了。看明白了吧,restrict關鍵字起作用了,編譯器檢測到指針a和b都使用了restrict關鍵字,也就是說,它們所指向的空間都只能通過指針a和b訪問,不會有其他途徑。這個時候,編譯器就可以放心大膽地進行優化了,直接把2賦給了eax,而不用再從內存中獲取了。這樣,f的執行效率也提高了。這裡還有一點需要注意,C++程序並不支持restrict關鍵字,但是可以使用「__restrict」關鍵字。

- EOF -

關注『CPP開發者』

看精選C++技術文章 . 加C++開發者專屬圈子

↓↓↓

點讚和在看就是最大的支持❤️

相關焦點

  • 容易引起誤解的「restrict to"
    have restricted the use of fen-phen.(2018年閱讀)但是值得注意的是( it's notewhorthy that)一旦出現restrict…to…的時候,很多人就很容易出現理解上的錯誤。
  • 各種開源彙編、反彙編引擎的非專業比較
    如果要對彙編指令進行分析和操作,要麼自己研究Intel指令集寫一個,要麼就用現成的開源引擎。自己寫太浪費時間,又是苦力活,還容易出錯,所以還是使用現成的好一點。  這裡對我曾使用過的比較流行的反彙編引擎做個比較,我使用過的反彙編引擎有:  1.
  • 智能合約安全系列文章反彙編·下篇
    前言上篇我們詳細分析了智能合約反彙編後的代碼內容,包括多個反彙編指令的含義,數據在棧中的存儲方式,並通過上下文關聯關係梳理代碼邏輯。本篇我們將繼續分析上篇遺留的反彙編代碼,通過上篇學習我們已對反彙編指令在棧和內存存儲的有了一定了解,該篇我們將重點來分析反彙編指令表示的代碼邏輯。
  • 知名公司面試題:談談你對volatile關鍵字的理解
    作為一名java程式設計師,求職面試時,關於volatile關鍵字時常會遇到。張工最近到某知名網際網路公司面試,面試官提出這樣的一個問題:談談你對volatile關鍵字的理解張工一時間沒有回答上來,面試官:你都工作三年了,怎麼對volatile關鍵字都沒掌握啊。
  • 反舞弊調查的特徵關鍵字排查
    根據我們的反舞弊調查實踐,舞弊行為所體現的特徵與其所處的行業、職務和涉案項目常常能形成一定的對應共性關係,比如共性的有:轉帳、匯款、現金等,個案相關的有:人名、設備名、個人生活軌跡、習慣等。如何快速、有效地設定關鍵字來進行第一次數據篩查?如何在初步排查基礎上,進一步結合案情和排查結果進行反覆深入的滾動篩查?涉案關鍵字一般隱藏在哪些文件裡?
  • DSP編程技巧之17---非常「關鍵」的關鍵字
    C28x的編譯器支持所有的標準C89的關鍵字,包括const、volatile和register,標準的C99關鍵字,包括inline和restrict,以及支持TI自定義的擴展關鍵字__cregister、__asm,和__interrupt;對於FPU的操作,還支持restrict關鍵字。
  • 第一個編譯器是怎麼來的~
    因此第一個C語言編譯器的原型完全可能是用B語言或者混合B語言與PDP彙編語言編寫的。但是B語言的效率比較低,如果全部用彙編語言來編寫,不僅開發周期長、維護難度大,更可怕的是失去了高級程序設計語言必需的移植性。
  • 混合使用C、C++和彙編語之:內聯彙編和嵌入型彙編的使用
    例如,在下面幾種情況中必須使用內聯彙編或嵌入型彙編。·程序中使用飽和算術運算(Saturatingarithmetic),如SSAT16和USAT16指令。·程序中需要對協處理器進行操作。·在C或C++程序中完成對程序狀態寄存器的操作。使用內聯彙編編寫的程序代碼效率也比較高。
  • restrain & restrict
    restrain & restrictrestrain1. to stop yourself from feeling an emotion or doing sth that you would like to do. 約束(自己);控制(自己);忍住◆ John managed to restrain his anger.
  • 零時科技 | 智能合約安全系列文章反彙編·上篇
    前言通過上一篇反編譯文章的學習
  • 深度解析volatile關鍵字,就是這麼簡單
    本文章講解的內容是深入了解volatile關鍵字,建議對著示例項目閱讀文章,示例項目連結如下:https://github.com/TanJiaJunBeyond/VolatileDemo查看彙編代碼的hsdis-amd64.dylib文件連結如下:https://github.com/TanJiaJunBeyond/VolatileDemo/blob/master/hsdis-amd64
  • 反彙編代碼還原之加減乘
    加法的高級代碼與反彙編而加法也特別簡單,配合上一篇講解的優化方式,可以很好的還原。加法對應的 彙編 **add** 指令.eax = edx + 2; edx = var10 var10 = 0xA繼續變化edx = 0xAeax = edx + 2繼續變化eax = 10 + 2此時我們就反推出了加法原型。我不知道它人是否是這種反彙編風格,我是從下往上,按照上下文來進行還原。
  • 理解 C 語言中的關鍵字 extern
    所以就讓我先來說說extern關鍵字在變量和函數上的應用。最基本的extern關鍵字擴展了變量和函數的可見度。這可能就是它為什麼命名為extern的原因。幾乎所有人都知道聲明和定義變量(函數)的意義,但是為了這篇文章的完整性,我想弄清楚它們。聲明一個變量(函數)只是表明這個變量(函數)存在於程序的某個地方,並沒有為它們分配內存。
  • ARM彙編指令:.align理解和用法
    偽指令的作用是:告訴彙編程序,本偽指令下面的內存變量必須從下一個能被Num整除的地址開始分配。如果下一個地址正好能被Num整除,那麼,該偽指令不起作用,否則,彙編程序將空出若干個字節,直到下一個地址能被Num整除為止。
  • 反彙編代碼還原之除數為非2的冪
    反彙編代碼還原之除數為2的冪反彙編代碼還原之加減乘* 點擊文字即可跳轉文章1.1 簡介除法在非2的冪優化上,採用的是除法轉變為乘法的形式,在學習這方面知識的時候我們先了解下簡單的數學知識.這樣方便我們用科學計算器來進行運算)。
  • const關鍵字到底該什麼用?
    關註上方百問科技,選擇置頂嵌入式乾貨,及時送達---文 | 守望先生經授權轉載自公眾號編程珠璣(id:shouwangxiansheng)前言我們都知道使用const關鍵字限定一個變量為只讀,但它是真正意義上的只讀嗎?實際中又該如何使用const關鍵字?
  • 英語課程標準 回復關鍵字 課程標準 ​
    (後期資料群內更新分享)三湘名校教育聯盟五市十校教研教改共同體2021屆高三11月大聯考英語試卷+答案  後臺回復關鍵字 三湘超級中學學法指導回復關鍵字   超級中學英語課程標準  回復關鍵字  課程標準北師大(老版本和部分新版本)版本資源回復關鍵字  北師大外研版(老版本和部分新版本)版本資源回復關鍵字  外研版譯林版
  • const關鍵字到底該什麼用
    實際中又該如何使用const關鍵字?在解答這些問題之前,我們需要先理解const關鍵字的基本使用。本文說明C中的const關鍵字,不包括C++。基本介紹const是constant的簡寫,是不變的意思。但並不是說它修飾常量,而是說它限定一個變量為只讀。
  • @程式設計師,快來速取硬核的彙編語言知識大全!
    用彙編語言編寫的原始碼和本地代碼是一一對應的。因而,本地代碼也可以反過來轉換成彙編語言編寫的代碼。把本地代碼轉換為彙編代碼的這一過程稱為反彙編,執行反彙編的程序稱為反彙編程序。哪怕是 C 語言編寫的原始碼,編譯後也會轉換成特定 CPU 用的本地代碼。而將其反彙編的話,就可以得到彙編語言的原始碼,並對其內容進行調查。
  • ARM中ADS環境下C語言和彙編語言混合編程及示例
    稍大規模的嵌入式程序設計中,大部分的代碼都是用C來編寫的,主要是因為C語言具有較強的結構性,便於人的理解,並且具有大量的庫支持。但對於一寫硬體上的操作,很多地方還是要用到彙編語言,例如硬體系統的初始化中的CPU 狀態的設定,中斷的使能,主頻的設定,RAM控制參數等。