我试着理解gcc x64组织堆栈的方式,一个小程序生成这个asm
(gdb) disassemble *main
Dump of assembler code for function main:
0x0000000000400534 <main+0>: push rbp
0x0000000000400535 <main+1>: mov rbp,rsp
0x0000000000400538 <main+4>: sub rsp,0x30
0x000000000040053c <main+8>: mov DWORD PTR [rbp-0x14],edi
0x000000000040053f <main+11>: mov QWORD PTR [rbp-0x20],rsi
0x0000000000400543 <main+15>: mov DWORD PTR [rsp],0x7
0x000000000040054a <main+22>: mov r9d,0x6
0x0000000000400550 <main+28>: mov r8d,0x5
0x0000000000400556 <main+34>: mov ecx,0x4
0x000000000040055b <main+39>: mov edx,0x3
0x0000000000400560 <main+44>: mov esi,0x2
0x0000000000400565 <main+49>: mov edi,0x1
0x000000000040056a <main+54>: call 0x4004c7 <addAll>
0x000000000040056f <main+59>: mov DWORD PTR [rbp-0x4],eax
0x0000000000400572 <main+62>: mov esi,DWORD PTR [rbp-0x4]
0x0000000000400575 <main+65>: mov edi,0x400688
0x000000000040057a <main+70>: mov eax,0x0
0x000000000040057f <main+75>: call 0x400398 <printf@plt>
0x0000000000400584 <main+80>: mov eax,0x0
0x0000000000400589 <main+85>: leave
0x000000000040058a <main+86>: ret
edi
和rsi
edi
和rsi
的任何恢复值
edi
和rsi
保存在delta 0x20 - 0x14 = 0xC的位置,而不是连续区域,是否有意义?以下是源代码
int mix(int a,int b,int c,int d,int e,int f, int g){
return a | b | c | d | e | f |g;
}
int addAll(int a,int b,int c,int d,int e,int f, int g){
return a+b+c+d+e+f+g+mix(a,b,c,d,e,f,g);
}
int main(int argc,char **argv){
int total;
total = addAll(1,2,3,4,5,6,7);
printf("result is %d\n",total);
return 0;
}
修改
似乎堆栈已经存储了对addAll
和total
的esi,rdi,第7个参数调用,它应该占用4x8 = 32(0x20)字节,由于某些原因它会向上舍入到0x30。
答案 0 :(得分:2)
我不知道您的原始代码,但本地也存储在堆栈中,当您有一些局部变量时,空间也被“分配”。同样出于对齐的原因,他可以“舍入”到16的下一个倍数。我猜你有一个本地用于将你的addAll的结果传递给printf,并存储在rbp-04。
我刚看了你的链接ABI - 它说被调用者必须恢复rdi和rsi?它已在第15页说明,脚注:
请注意,与Intel386 ABI相比,%rdi和%rsi属于被调用函数,而不是 来电者。
Afaik用于将第一个参数传递给被调用者。
0xC是12.这也来自对齐,你可以看到,他只需要存储edi而不是rdi,为了对齐目的我假设他将它对齐在4字节边框上,而si是rsi,这是64位并在8字节边界上对齐。
答案 1 :(得分:1)
2:ABI明确表示rdi / rsi不需要被被调用的函数保存;见第15页和脚注5。
1和3:不确定;可能是堆栈对齐问题。