4.2.2 传递函数参数

在x86中,最常见的传参方式是cdecl:

  1. push arg3
  2. push arg2
  3. push arg1
  4. call f
  5. add esp, 4*3

被调用函数通过栈指针访问函数参数。因此,这就是为什么要在函数f()执行之前将数据放入栈中的原因。

4.2.2 传递函数参数 - 图1

来看一下其它调用约定。没有意义也没有必要强迫程序员一定要使用栈来传递参数。

这不是必需的,可以不使用栈,通过其它方式来实现。

例如,可以为参数分配一部分堆空间,存入参数,将指向这部分内存的指针存入EAX,这样就可以了。然而,在x86和ARM中,使用栈传递参数还是更加方便的。

另外一个问题,被调用的函数并不知道有多少参数被传递进来。有些函数可以传递不同个数的参数(如:printf()),通过一些说明性的字符(以%开始)才可以判断。如果我们这样调用函数

printf("%d %d %d", 1234);

printf()会传⼊入1234,然后另外传入栈中的两个随机数字。这就让我们使用哪种方式调用 main()函数变得不重要,像main(),main(int argc, char *argv[])main(int argc, char *argv[], char *envp[])

事实上,CRT函数在调用main()函数时,使用了下面的指令:  #!bash push envp push argv push argc call main ...

如果你使用了没有参数的main()函数,尽管如此,但它们仍然在栈中,只是无法使用。如果你使用了main(int argc, char *argv[]),你可以使用两个参数,第三个参数对你的函数是“不可见的”。如果你使用main(int argc)这种方式,同样是可以正常运行的。