我机器的版本
FreeBSD fb7.arraynetworks.com.cn 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Sun Feb 24 10:35:36 UTC 2008 root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64
NASM version 2.10.07 compiled on Apr 11 2013
-
section .data
-
message:
-
db 'hello, world!', 0
-
section .text
-
global _start
-
_start:
-
mov rax, 4
-
mov rdi, 1
-
mov rsi, message
-
mov rdx, 13
-
syscall
-
mov rax, 1
-
xor rdi, rdi
-
syscall
如果需要解释的话,_start相当于函数的入口
rax传递的是调用的syscall id
rdi第一个参数,fd
rsi第二个参数,字符串
rdx第三个参数,字符串长度。
这个是x86-64的约定,参数依次为
RDI, RSI, RDX, RCX, R8, R9.如果再有就需要用栈了。
写一个C代码,反汇编看看也能得到上面的结论。
-
long add(long a, int b, int c, int d, int e, int f, int g, int h, int i, int j, long k){
-
long x = a + b + c + d + e + f + g;
-
x = x + g + h + i +j + k;
-
return x;
-
}
-
-
int main(){
-
long x = add(0xfffffffff2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
-
return 0x11;
-
}
反汇编会得到如下的结果
-
(gdb) disassemble main
-
Dump of assembler code for function main:
-
0x0000000000400600 : push rbp
-
0x0000000000400601 : mov rbp,rsp
-
0x0000000000400604 : sub rsp,0x40
-
0x0000000000400608 : mov esi,0x8
-
0x000000000040060d : mov edi,0x400700
-
0x0000000000400612 : mov eax,0x0
-
0x0000000000400617 : call 0x40042c
-
0x000000000040061c : mov DWORD PTR [rsp+32],0xc
-
0x0000000000400625 : mov DWORD PTR [rsp+24],0xb
-
0x000000000040062d : mov DWORD PTR [rsp+16],0xa
-
0x0000000000400635 : mov DWORD PTR [rsp+8],0x9
-
0x000000000040063d : mov DWORD PTR [rsp],0x8
-
0x0000000000400644 : mov r9d,0x7
-
0x000000000040064a : mov r8d,0x6
-
0x0000000000400650 : mov ecx,0x5
-
0x0000000000400655 : mov edx,0x4
-
0x000000000040065a : mov esi,0x3 <----32 bit
-
0x000000000040065f : mov rdi,0xfffffffff2 <----64bit register
-
0x0000000000400669 : call 0x400570
-
0x000000000040066e : mov DWORD PTR [rbp-8],rax
-
0x0000000000400672 : mov eax,0x11
1方面能看出寄存器当参数的顺序,另一方面,居然能用32位就用32位,装不下才需要64位,不知道为啥。
另外一个需要注意的问题是,x86-64上,栈是16字节对齐的,比如如果没有参数需要从栈上传递的话,尽管返回指令压栈只占用8个字节,
但实际上,也会占用16个字节,比如下面的C代码
-
long add(long a, int b, int c){
-
long x = a + b + c;
-
return x;
-
}
-
-
void print(){
-
}
-
int main(){
-
long x = add(0xfffffffff2, 3, 4);
-
print();
-
return 0x11;
-
}
反汇编得到的结果如下
-
(gdb) disassemble main
-
Dump of assembler code for function main:
-
0x0000000000400570 : push rbp
-
0x0000000000400571 : mov rbp,rsp
-
0x0000000000400574 : sub rsp,0x10
-
0x0000000000400578 : mov edx,0x4
-
0x000000000040057d : mov esi,0x3
-
0x0000000000400582 : mov rdi,0xfffffffff2
-
0x000000000040058c : call 0x400530
-
0x0000000000400591 : mov DWORD PTR [rbp-8],rax
-
0x0000000000400595 : mov eax,0x0
-
0x000000000040059a : call 0x400560
-
0x000000000040059f : mov eax,0x11
-
0x00000000004005a4 : leave
-
0x00000000004005a5 : ret
-
0x00000000004005a6 : nop
-
0x00000000004005a7 : nop
-
0x00000000004005a8 : nop
-
0x00000000004005a9 : nop
-
0x00000000004005aa : nop
-
0x00000000004005ab : nop
-
0x00000000004005ac : nop
-
0x00000000004005ad : nop
-
0x00000000004005ae : nop
-
0x00000000004005af : nop
执行call add指令之前后的rsp变化如下
-
0x000000000040058c in main ()
-
(gdb) info reg rsp
-
rsp 0x7fffffffeb00 0x7fffffffeb00
-
(gdb) nexti
-
-
Breakpoint 2, 0x0000000000400534 in add ()
-
(gdb) info reg rsp
-
rsp 0x7fffffffeaf0 0x7fffffffeaf0
-
(gdb) x /3xg 0x7fffffffeaf0
-
0x7fffffffeaf0: 0x00007fffffffeb10 0x0000000000400591
-
0x7fffffffeb00: 0x0000000000000001
-
(gdb)
可以看出栈顶变化了0x10也就是16个字节,其中,第一个进栈的是0x000....1,后一个进栈是是400591,这个是add函数返回后继续执行的指令。
愿意的话可以自己试一下另外一中情况,比如:
-
long add(long a, int b, int c, int d, int e, int f, int g){
-
long x = a + b + c + d + e + f + g;
-
return x;
-
}
-
-
int main(){
-
long x = add(0xfffffffff2, 3, 4, 5, 6, 7, 8);
-
return 0x11;
-
}
反汇编代码
-
0x0000000000400590 <main+0>: push rbp
-
0x0000000000400591 <main+1>: mov rbp,rsp
-
0x0000000000400594 <main+4>: sub rsp,0x18
-
0x0000000000400598 <main+8>: mov DWORD PTR [rsp],0x8
-
0x000000000040059f <main+15>: mov r9d,0x7
-
0x00000000004005a5 <main+21>: mov r8d,0x6
-
0x00000000004005ab <main+27>: mov ecx,0x5
-
0x00000000004005b0 <main+32>: mov edx,0x4
-
0x00000000004005b5 <main+37>: mov esi,0x3
-
0x00000000004005ba <main+42>: mov rdi,0xfffffffff2
-
0x00000000004005c4 <main+52>: call 0x400530 <add>
-
0x00000000004005c9 <main+57>: mov DWORD PTR [rbp-8],rax
-
0x00000000004005cd <main+61>: mov eax,0x11
-
0x00000000004005d2 <main+66>: leave
-
0x00000000004005d3 <main+67>: ret
多了一个参数,寄存器放不下,只能放到栈上。这时候看call add前后的rsp寄存器变化
-
(gdb) nexti
-
0x00000000004005c4 in main ()
-
(gdb) info reg rsp
-
rsp 0x7fffffffeaf8 0x7fffffffeaf8
-
(gdb) nexti
-
-
Breakpoint 2, 0x0000000000400534 in add ()
-
(gdb) info reg rsp
-
rsp 0x7fffffffeae8 0x7fffffffeae8
-
(gdb) x /3xg 0x7fffffffeae8
-
0x7fffffffeae8: 0x00007fffffffeb10 0x00000000004005c9
-
0x7fffffffeaf8: 0x0000000000000008
-
(gdb)
虽然栈顶也变化了0x10,但是依次是参数8和下一个指令的地址4005c9。
阅读(2165) | 评论(0) | 转发(0) |