首页
社区
课程
招聘
[翻译]X86-64下的栈帧布局简介
发表于: 2015-5-14 15:21 19396

[翻译]X86-64下的栈帧布局简介

2015-5-14 15:21
19396

翻译:稻天
原文网址:http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64
转载请注明出处

数月前,我写过一篇文章《Where the top of the stack is on x86》,文章旨在厘清x86环境下一些被误解的栈使用场景。文章中描述了一个典型函数调用的图表用以展示呈现栈帧布局。

这篇文章里,我将探究x86框架下的64位版本的栈帧布局,并主要关注Linux和其他遵循System V AMD64 ABI调用约定的操作系统。Windows下的ABI会稍有不同,文章最后会简要的谈及。


[*]丰富的寄存器
x86只有8个通用寄存此供使用(eax, ebx, ecx, edx, ebp, esp, esi, edi)。x64将它们扩展为64位(前缀由“e”变更为“r”),并且新增了8个寄存器(r8, r9, r10, r11, r12, r13, r14, r15)。由于x86下一些寄存器有特殊的用途和意义而不是真正意义上的“通用”(尤其是ebp和esp寄存器),使得这些新增的特性产生的效用远不止是变大变多。


[*]参数传递
从ABI来看,函数开始的6个整数或指针类型的参数将通过寄存器传递参数,第一个参数保存在rdi中,第二个保存在rsi中,接下来依次保存在rdx,rcx,r8,r9。从第7个参数开始,接下来的所有参数都将通过栈传递。


[*]栈帧
有了以上的基础知识,让我们来看一下C函数的栈帧布局:

long myfunc(long a, long b, long c, long d,
            long e, long f, long g, long h)
{
    long xx = a * b * c * d * e * f * g * h;
    long yy = a + b + c + d + e + f + g + h;
    long zz = utilfunc(xx, yy, xx % yy);
    return zz + 20;
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 3
支持
分享
最新回复 (15)
雪    币: 63
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
自己先顶一下    顶!d=====( ̄▽ ̄*)b
2015-5-14 16:11
0
雪    币: 242
活跃值: (16)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
第一个参数保存在rdi中,第二个保存在rsi中,接下来依次保存在rdx,rcx,r8,r9


你确定? 什么平台啊?自己写代码试试~
2015-5-14 18:18
0
雪    币: 242
活跃值: (16)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
抱歉,没有看完


Windows x64 ABI

X64下,Windows 实现了一套和AMD64ABI有些许不同的ABI
2015-5-14 18:20
0
雪    币: 63
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
Linux和windows的标准是不一样的,我翻译完这篇文章后也认真的查看了相关的汇编代码,确实如此的
2015-5-15 09:23
0
雪    币: 22
活跃值: (242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
int Add(int a,int b,int c,int d,int e)
{
    return a+b+c+d+e;
}

        Add(2,3,4,5,6);
000000013FBD2DF1  mov         dword ptr [rsp+20h],6  
000000013FBD2DF9  mov         r9d,5  
000000013FBD2DFF  mov         r8d,4  
000000013FBD2E05  mov         edx,3  
000000013FBD2E0A  mov         ecx,2  
000000013FBD2E0F  call        Add (13FBD100Fh)  
调用的时候只有前4个参数是寄存器传参
2015-5-16 21:34
0
雪    币: 22
活跃值: (242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
7
[QUOTE=GeekCheng;1371040]int Add(int a,int b,int c,int d,int e)
{
    return a+b+c+d+e;
}

        Add(2,3,4,5,6);
000000013FBD2DF1  mov         dword ptr [rsp+20h],6  
000000013FBD2...[/QUOTE]

不对啊,怎么还会有edx和ecx
2015-5-16 21:39
0
雪    币: 63
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
编译器是使用edx和ecx,但是真正参与传递参数是rdx和rcx

如果你要测试,我建议你使用负数,这样,能使用到参数的最高位,这样,编译器就不会“偷懒”了
2015-5-18 14:39
0
雪    币: 22
活跃值: (242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
9
懂了
int Add(LONGLONG a,LONGLONG b,LONGLONG c,LONGLONG d,int e)
{

        return a+b+c+d+e;
}

Add(-2,-3,-4,-5,6);
000000013FBA1041  mov         dword ptr [rsp+20h],6  
000000013FBA1049  mov         r9,0FFFFFFFFFFFFFFFBh  
000000013FBA1050  mov         r8,0FFFFFFFFFFFFFFFCh  
000000013FBA1057  mov         rdx,0FFFFFFFFFFFFFFFDh  
000000013FBA105E  mov         rcx,0FFFFFFFFFFFFFFFEh  
000000013FBA1065  call          Add (13FBA100Ah)
2015-5-18 14:49
0
雪    币: 63
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
现象不一定能说明本质,但多实验肯定会更加接近本质
2015-5-18 16:54
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
[QUOTE=GeekCheng;1371040]int Add(int a,int b,int c,int d,int e)
{
    return a+b+c+d+e;
}

        Add(2,3,4,5,6);
000000013FBD2DF1  mov         dword ptr [rsp+20h],6  
000000013FBD2...[/QUOTE]

那么并没有用rsi和rdi传参
2015-5-18 17:09
0
雪    币: 22
活跃值: (242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
12
文章中说了,Windows自己实现了与AMD 不同的ABI,Linux与Windows不一样,楼上也说了
2015-5-18 18:45
0
雪    币: 256
活跃值: (25)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
讲解的好棒~刚好解决困惑~感谢!
2015-5-22 09:48
0
雪    币: 63
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
对你有帮助就好,翻译文章就是为了减少language gaps
2015-5-26 14:52
0
雪    币: 1644
活跃值: (53)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
感谢分享。
2015-6-4 22:12
0
雪    币: 63
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
谢谢支持!
2015-6-9 17:49
0
游客
登录 | 注册 方可回帖
返回
//