以上操作,我們只考慮了直線**的行為,即指令按順序執行。但是還有一些**,比如條件語句、迴圈語句和分支語句,要求有條件的執行,這時需要根據資料測試的結果來改變條件碼,結合跳轉指令決定操作執行的順序。
條件傳送指令
實現條件操作的傳統方法是利用控制的條件轉移。當條件滿足時,程式沿著一條執行路徑進行,而當條件不滿足時,就走另一條路徑。這種機制簡單而通用,但是在現代處理器上,可能效率不高。
資料的條件轉移是一種替代的策略。這種方法先計算乙個條件操作的兩種結果,然後再根據條件是否滿足從而選取乙個。條件傳送指令更好地匹配了現代處理器的效能特性。
看如下例子:
條件表示式同條件語句相似。關鍵就在於彙編**第8行的cmovl指令,這條指令除了只在指定的條件滿足時才執行資料傳送之外,它的語法與mov指令的相同。
考慮下面的條件表示式和賦值的通用形式:
v = test-expr
?then-expr:lese-expr;
編譯器產生的**,條件轉移形式:
if (!test-expr)
goto false;
v = then-expr;
goto done;
false:
v = else-expr;
done:
基於條件傳送的**:
vt = then-expr;
v =else
-expr;
t = test-expr;
if(t) v = vt;
這個序列中的最後一條語句是用條件傳送實現的——只有當測試條件t滿足時,vt的值才會被複製到v中。
現代處理器通過使用流水線來獲得高效能,即重疊連續指令的步驟。當機器遇到條件跳轉時,它常常不能確定是否要進行跳轉。處理器會進行分支**,但是**錯誤要求處理器丟掉它為跳轉指令後所有指令已經做了的工作,招致很嚴重的懲罰,導致效能下降。但是使用條件傳送也不是總會改進**的效率。例如,如果then-expr或者else-expr的求值需要大量的計算,那麼當相對應的條件不滿足時,這些工作就白費了。編譯器必須考慮浪費的計算和由於分支**錯誤所造成的效能處罰之間的相對效能。
switch語句
switch語句可以根據乙個整數索引值進行多重分支。它通過跳轉表實現。
其中jt就是跳轉表。可以觀察到,跳轉表對重複情況的處理就是簡單地對表項4和6用同樣的**標號(loc_ d),而對於缺失情況的處理就是對表項1和5使用預設情況的標號(loc_def)。
上述**的彙編**如下:
執行switch語句的關鍵步驟是通過跳轉表來訪問**位置,彙編**中,跳轉錶用以下宣告:
這些宣告表明,在「.rodata」(唯讀資料,read-only data )的目標**檔案的段中,應該有一組7個「long」(4個位元組),每個字的值都是與指定的彙編**標號相關的指令位址。標號.l7標記出這段分配位址的起始。
使用跳轉表是一種非常有效的實現多重分支的方法。在我們的例子中,程式可以只用一次跳轉表引用就分支到5個不同的位置;當switch語句有上百種情況的時候,也可以只用一次跳轉表訪問去處理。
程式的機器級表示二(控制)
目錄 1.條件碼 2.跳轉指令 3.條件傳送指令 4.switch語句 實現有條件的行為 lea mov指令不設定條件碼 比較和測試指令 cmp類似 sub 指令的行為,只設定條件碼而不更新目標暫存器。test類似and,只設定條件碼而不更新目標暫存器。訪問條件碼 用法 條件碼組合,設定某個位元組 ...
程式的機器級表示
三種 立即數 常數值,在att格式的彙編 中,書寫格式是 整數,如 123 0x12 暫存器 如 32位的 eax 16位的 ax 8位的 al 儲存器引用 mov 同等傳送,即倆者的大小一致 如 movb byte,movew word,movel longword dw movs movz 不同...
程式的機器級表示
32位和64位 instruction system architecture 程式計數器pc eip 整數暫存器 8個每個32位 有的用來記錄狀態,有的用來儲存臨時資料,區域性變數,返回值 3.條件碼暫存器 指標都是雙字 char short long 其他4位元組 movb movw movl ...