关于函数调用的参数传递

2009年5月26日 | 由 helight | 800字 | 阅读大约需要2分钟 | 归档于 kernel | 标签 #kernel

前几天和王老师在调式一个程序,调试结果怎么都不正确。其实形式很简单: printf("%d; %d”, sum(), m); m是一个静态变量,在sum中改变,但是打印结果还是没有变化。 当然在后来我又作了一个测试发现在gcc编译的程序中他是以左优先的,也就是先打印计算m的结果,让后在计算sum的结果,再打印。

昨天在使用汇编分析程序的时候才发现真是这样的,在汇编程序中参数一般使用寄存器或是堆栈来传递,在gcc的编译中使用这几乎同时使用了这两种方式。例如下面这段程序

#include <stdio.h>

int main(int args, char *argv[])
{
        printf("num: %d num: %d \n", 5, 6);//这里printf使用了三个参数

        return 0;
} 

其汇编程序如下的:(使用:”gcc -S hello.c“ 生成其相应的汇编程序)

        .file   "hello.c"
        .section        .rodata
.LC0:
        .string "num: %d num: %d \n"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        subl    $20, %esp
        movl    $6, 8(%esp) 	//这里处理第三个参数
        movl    $5, 4(%esp) 	//这里是第二个参数
        movl    $.LC0, (%esp)	//这里是第一个参数
        call    printf        		//这里调用printf函数
        movl    $0, %eax
        addl    $20, %esp
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
        .section        .note.GNU-stack,"",@progbits    

根据上面的代码可以清楚的看到参数处理顺序的先后,从而导致了执行结果的先后。 下面在来一个简单的例子:

#include <stdio.h>

int main(int args, char *argv[])
{
	int i  10

        printf("i: %d i+: %d \n", i++, i++);//这里printf使用了三个参数

        return 0;
} 

其汇编程序如下的:(使用:”gcc -S hello.c“ 生成其相应的汇编程序)

        .file   "hello.c"                                                     
        .section        .rodata
.LC0:
        .string "i: %d i+: %d \n"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp	//将堆栈指针放到ebp中
        pushl   %ecx			//这里是保存堆栈指针
        subl    $36, %esp		//
        movl    $10, -8(%ebp)	//
        movl    -8(%ebp), %edx	//这两句是把10放到edx中
        addl    $1, -8(%ebp)
        movl    -8(%ebp), %eax	//这两句是把i++放到eax中
        addl    $1, -8(%ebp)	//这里再次把i加1
        movl    %edx, 8(%esp)	//这里是第三个参数 这里的结果是10
        movl    %eax, 4(%esp)	//这里是第二个参数 这里的结果是11
        movl    $.LC0, (%esp)	//这里是第一个参数 这里的结果是"i: %d i+: %d \n"
        call    printf			//调用printf
        movl    $0, %eax		//返回值放到eax中
        addl    $36, %esp
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (Debian 4.3.2-1.1) 4.3.2"
        .section        .note.GNU-stack,"",@progbits
argc.s                                                                        1,2-9          All
"argc.s" 33L, 576C