C語言其實是個絕世高手,它一直隐藏"彙編“的身份,别人以為彙編是彙編,C語言隻是默默一笑: 彙編隻是我的代理人。
Q: 選擇語句if是如何對應彙編的?
A:
int i;
int j;
if (i == 1)
j = 0;
else
j = 1;
0000000100000f92 cmpl $0x1, -0x14(%rbp) // i == 1 ?
0000000100000f96 jne 0x100000fa8
0000000100000f9c movl $0x0, -0x18(%rbp) // j = 0
0000000100000fa3 jmp 0x100000faf
0000000100000fa8 movl $0x1, -0x18(%rbp) // j = 1
0000000100000faf xorl %eax, %eax
判斷i是否為1: cmpl指令判斷相等; jne代表不為0跳轉(cmp為減運算); jmp為無條件跳轉,此處為i == 1的情況。
Q: for循環是如何對應彙編的?
A:
int i;
int j;
for(i = 1; i < 10; ++i)
j = i;
0000000100000f82 movl $0x1, -0x14(%rbp) // i = 1
0000000100000f89 cmpl $0xa, -0x14(%rbp) // i < 10
0000000100000f8d jge 0x100000fa7 // when i >= 10, jump out
0000000100000f93 movl -0x14(%rbp), %eax // now, i < 10
0000000100000f96 movl %eax, -0x18(%rbp) // j = i
0000000100000f99 movl -0x14(%rbp), %eax
0000000100000f9c addl $0x1, %eax // ++i
0000000100000f9f movl %eax, -0x14(%rbp)
0000000100000fa2 jmp 0x100000f89
0000000100000fa7 xorl %eax, %eax
對于for循環,比較和跳轉指令實作初始化和判斷跳轉功能。
Q: while循環如何對應彙編?
A:
int i = 1;
int j;
while(i < 10) {
j = i;
++i;
}
0000000100000f82 movl $0x1, -0x14(%rbp) // i = 1
0000000100000f89 cmpl $0xa, -0x14(%rbp) // i >= 10 ?
0000000100000f8d jge 0x100000fa7 // jump out
0000000100000f93 movl -0x14(%rbp), %eax
0000000100000f96 movl %eax, -0x18(%rbp) // j = i
0000000100000f99 movl -0x14(%rbp), %eax
0000000100000f9c addl $0x1, %eax // ++i
0000000100000f9f movl %eax, -0x14(%rbp)
0000000100000fa2 jmp 0x100000f89
0000000100000fa7 xorl %eax, %eax
while和if語句很相近,因為它們表達的含義是相近的。
Q: break對應彙編是什麼?
A:
int i = 1;
int j;
while(i < 10) {
if (i > 5)
break;
j = i;
++i;
}
0000000100000f72 movl $0x1, -0x14(%rbp)
0000000100000f79 cmpl $0xa, -0x14(%rbp)
0000000100000f7d jge 0x100000fa6
0000000100000f83 cmpl $0x5, -0x14(%rbp) // i > 5 ?
0000000100000f87 jle 0x100000f92 // i <= 5, continue
0000000100000f8d jmp 0x100000fa6 // i > 5, jump out
0000000100000f92 movl -0x14(%rbp), %eax
0000000100000f95 movl %eax, -0x18(%rbp)
0000000100000f98 movl -0x14(%rbp), %eax
0000000100000f9b addl $0x1, %eax
0000000100000f9e movl %eax, -0x14(%rbp)
0000000100000fa1 jmp 0x100000f79
0000000100000fa6 xorl %eax, %eax
break實際也隻是比較和跳轉指令的代名詞,continue也是類似就不再贅述。
Q: switch/case語句如何對應彙編?
A:
int i; // not initialize it on purpose
int j;
switch(i) {
case 1:
j = 1;
break;
case 2:
j = 2;
break;
default:
j = 0;
break;
}
0000000100000f62 movl -0x14(%rbp), %edi
0000000100000f65 movl %edi, %eax // i is in %eax
0000000100000f67 subl $0x1, %eax // i == 1?
0000000100000f6a movl %edi, -0x1c(%rbp)
0000000100000f6d movl %eax, -0x20(%rbp)
0000000100000f70 je 0x100000f8f // case 1
0000000100000f76 jmp 0x100000f7b
0000000100000f7b movl -0x1c(%rbp), %eax
0000000100000f7e subl $0x2, %eax // i == 2?
0000000100000f81 movl %eax, -0x24(%rbp)
0000000100000f84 je 0x100000f9b // case 2
0000000100000f8a jmp 0x100000fa7
0000000100000f8f movl $0x1, -0x18(%rbp) // case 1: j = 1
0000000100000f96 jmp 0x100000fae
0000000100000f9b movl $0x2, -0x18(%rbp) // case 2: j = 2
0000000100000fa2 jmp 0x100000fae
0000000100000fa7 movl $0x0, -0x18(%rbp) // default: j = 0
0000000100000fae xorl %eax, %eax
又是一堆比較和跳轉指令,不過綜上所述,好像也沒有多少指令就表達了C語言大部分文法概念。
C語言和彙編其實很近,可參考:彙編和c隻有一步之近----小話c語言(19)
在計算機性能越來越高的情況下,堅持用彙編也許會稍許提升性能,但很可能已無實在意義,隻有純技術讨論的意義。當然,萬物都有局限,當C語言真的沒辦法直接表達,轉用彙編解決問題才是真正吃透了C語言.
作者: 陳曦
環境: MacOS 10.14.5 (Intel i5)
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Linux 3.16.83 (Ubuntu)
轉載請注明出處