2013-08-28 39 views
1

如果我有一个函数foo(arg1,arg2)。在IA32堆栈中,首先推入arg2,然后推入arg1,这样被调用函数通过%ebp + 8访问arg1并通过%ebp + 12访问arg2,但是推回的原因是什么? (我们的处理器提到了一些关于printf和count的内容,但我不太明白)。另外一般来说,调用函数从不传递参数的数量(有多少个参数),那么被调用函数怎么知道呢? 非常感谢!为什么在IA32堆栈过程中向后传递参数?

+1

这只是C调用约定。 C支持具有可变数量参数的函数,main()和printf()是常见的例子。通过将它们“向后”传递,第一个参数总是在已知位置。 –

+2

被调用者将“知道”有多少个参数,因为*编译器*在编译时知道并且看到保留适当数量的堆栈空间并生成代码来访问这些值。任何数量的var-args都会隐式转换为单个*数组*(加上数组的长度),并作为参考传递给被调用者。 – JimmyB

+0

而在C约定中,参数的可变数总是第一个?这是有道理的。然而,如果你按照正常顺序推动它们,你也会知道“参数的数量”总是最后一个,对吧? – user1849043

回答

1

在汇编层面,如果您以书面或倒序的方式在堆栈上传递参数并不重要,但所选方法必须与被调用函数所使用的方法相同。 C通常以相反的顺序推送值,因为它需要支持varargs - 可变数量的参数。如果按照书面顺序推送参数,那么得到第一个参数并不容易。

像Java或C#(以及.NET一般)等现代语言可以正常推送值,因为它们处理数组的附加参数(所以只有一个参数传递给被调用的函数 - 指向数组的指针)。

C的例子:

.data 
format: db "Your lucky number is %d", 0 
.... 

;code is equivalent to printf("Your lucky number is %d", 10); 
push dword 10 
push format 
call printf 

Java示例:

0: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
3: ldc   #3     // String Your lucky number is %d 
5: iconst_1 
6: anewarray  #4     // class java/lang/Object 
9: dup 
10: iconst_0 
11: bipush  10 
13: invokestatic #5     // Method java/lang/Integer.valueOf(I)Ljavava/lang/Integer; 
16: aastore 
17: invokevirtual #6     // Method java/io/PrintStream.printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; 
20: pop 
+0

“推10”从哪里来? – user1849043

+0

这是要打印的号码。 – user35443