歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

探究Linux下參數傳遞及查看和修改方法

X86-64下有16個64位寄存器,其中%rdi、%rsi、%rdx,%rcx、%r8、%r9用作傳遞函數參數,分別對應第1個參數、第2個參數直到第6個參數,如下圖所示(圖片來自網絡):

如果函數的參數個數超過6個,則超過的參數直接使用棧來傳遞。在被調用函數執行前,會先將寄存器中的參數壓入堆棧,之後的訪問會通過棧寄存器加上偏移位置來訪問。下面我們結合程序及其反匯編的結果來看一看。

相關閱讀:MIPS架構UBOOT和Linux參數傳遞 http://www.linuxidc.com/Linux/2011-04/34878.htm

C語言程序如下所示:
#include <stdio.h>
#include <stdlib.h>

static int func2(int i,int j)
{
int k;

k = i + j;
return k;
}

static int func(int fd,const char *ptr, int arg3, int arg4,int arg5,
int arg6, int arg7, int arg8)
{
int ret;

ret = arg7 + arg8;

func2(fd, arg3);

return ret;
}

int main(void)
{
func(12, "Hello,World!",3, 4, 5, 6, 7,8);

return 0;
}
  將上述程序保存為m.c,使用gcc加上-g選項編譯,然後使用gdb來進行調試,我們在main調用func的位置及func()和func2()函數三處加上斷點,如下所示:
(gdb) b m.c:26
Breakpoint 1 at 0x4004d4: file m.c, line26.
(gdb) b func
Breakpoint 2 at 0x4004ac: file m.c, line17.
(gdb) b func2
Breakpoint 3 at 0x40047e: file m.c, line8.
(gdb)
  然後我們在第一個斷點處停下,反匯編當前的main函數,查看參數傳遞方式,如下所示:
(gdb) disassemble /m main
Dump of assembler code for function main:
25 {
0x00000000004004cc <+0>: push%rbp
0x00000000004004cd <+1>: mov%rsp,%rbp
0x00000000004004d0 <+4>: sub $0x10,%rsp

26 func(12,"Hello,World!", 3,4, 5, 6, 7, 8);
=> 0x00000000004004d4<+8>: movl $0x8,0x8(%rsp)
0x00000000004004dc <+16>: movl $0x7,(%rsp)
0x00000000004004e3 <+23>: mov $0x6,%r9d
0x00000000004004e9 <+29>: mov $0x5,%r8d
0x00000000004004ef <+35>: mov $0x4,%ecx
0x00000000004004f4 <+40>: mov $0x3,%edx
0x00000000004004f9 <+45>: mov $0x400608,%esi
0x00000000004004fe <+50>: mov $0xc,%edi
0x0000000000400503 <+55>: callq 0x40048f<func>

27
28 return 0;
0x0000000000400508 <+60>: mov $0x0,%eax

29 }
0x000000000040050d <+65>: leaveq
0x000000000040050e <+66>: retq

End of assembler dump.
(gdb)
  在func(12, "Hello,World!", 3, 4, 5, 6, 7, 8);這行下面我們可以看到在使用callq指令調用func()函數之前,會使用mov指令將前6個參數的值分別保存在edi、esi、edx、ecx、r8d、r9d這個6個寄存器中,而將第7個和第8個參數存儲在棧上。這個結果和我們前面說的一致。

Copyright © Linux教程網 All Rights Reserved