C language function call parameter pressure stack Problems
Parameter stack entry sequence
Previously, I was asked during the interview whether the parameter stack-to-stack sequence was from left to right or from right to left during function call. I didn't think clearly at the time. I just said from right to left. In fact, this answer is not completely correct. In fact, the order of the inbound stack varies with the system architecture. For example, let's look at the following code:
#include
int test(int a, int b){ printf("address of a %x.\n", &a); printf("address of b %x.\n", &b); if ((unsigned int)&a > (unsigned int)&b) { printf("Push argument from left to right...\n"); } else { printf("Push argument from right to left...\n"); } return 0;}int main(){ test(1, 2); return 0;}
In 64-bit Ubuntu, the running result is from left to right.
Address of a 1ec62c.
Address of B 1ec628.
Push argument from left to right...
The result of 32-bit Ubuntu is: from right to left
Address of a bfd03290.
Address of B bfd03294.
Push argument from right to left...
First, Let's explain why the above Code can identify the order of the stack. First, you need to understand the following:
The stack compiled by gcc in C language is fromHigh address to low addressGrowth, that is to say, who first enters the stack, who has a large address, master this point, it is not difficult to write code.
What is in the stack during function calling?
Taking parameters from left to right as an example:
push arg0 -- High Addresspush arg1...push argnpush eippush ebp -- Low address
When a 32-bit system or a 64-bit system function is called, is the parameter stack Entry Method Different?
This problem was a problem not long ago. At that time, I was stupid. I have been paying attention to the parameter stack method of the 32-bit system for a long time. I always thought that the 64-bit system is the same and there is no difference, the following two points are summarized:
The 64-bit system first places the input parameters in the Register, and puts the register value into the stack in the specific implementation of the called function, then go to the stack and take the 64-bit system stack Parameter Storage order from left to right (because the register passed the value first)
Let's look at the disassembly below:
C code is the same as above Ubuntu 32-bit disassembly: int main () {804846d: 55 push % ebp 804846e: 89 e5 mov % esp, % ebp 8048470: 83 e4 f0 and $0xfffffff0, % esp 8048473: 83 ec 10 sub $0x10, % esp test (1, 2); 8048476: c7 44 24 04 02 00 00 movl $0x2, 0x4 (% esp) 804847d: 00 804847e: c7 04 24 01 00 00 00 movl $0x1, (% esp) 8048485: e8 8a ff call 8048414
Return 0; 804848a: b8 00 00 00 00 mov $0x0, % eax} int test (int a, int B) {8048414: 55 push % ebp 8048415: 89 e5 mov % esp, % ebp 8048417: 83 ec 18 sub $0x18, % esp printf ("address of a % x. \ n ", & a); 804841a: b8 60 85 04 08 mov $0x8048560, % eax 804841f: 8d 55 08 lea 0x8 (% ebp ), % edx 8048422: 89 54 24 04 mov % edx, 0x4 (% esp) 8048426: 89 04 24 mov % eax, (% esp) 8048429: e8 12 ff call 8048340
Return 0; 8048466: b8 00 00 00 00 mov $0x0, % eax} Ubuntu 64-bit disassembly: int main () {40056e: 55 push % rbp 40056f: 48 89 e5 mov % rsp, % rbp test (1, 2); 400572: be 02 00 00 00 mov $0x2, % esi 400577: bf 01 00 00 00 mov $0x1, % edi 40057c: e8 ac ff callq 40052d
Return 0; 400581: b8 00 00 00 00 mov $0x0, % eax} int test (int a, int B) {40052d: 55 push % rbp 40052e: 48 89 e5 mov % rsp, % rback 400531: 48 83 ec 10 sub $0x10, % rsp 400535: 89 7d fc mov % edi,-0x4 (% rbp) 400538: 89 75 f8 mov % esi,-0x8 (% rbp) printf ("address of a % x. \ n ", & a); 40053b: 48 8d 45 fc lea-0x4 (% rbp), % rax 40053f: 48 89 c6 mov % rax, % rsi 400542: bf 14 06 40 00 mov $0x400614, % edi 400547: b8 00 00 00 00 mov $0x0, % eax 40054c: e8 bf fe ff callq 400410
Return 0; 400567: b8 00 00 00 00 mov $0x0, % eax}
Look at the 32-bit ubuntu operating system, 8048476: it is true that the parameter is directly in the stack, 2 first into the stack, 1 then into the stack.
8048476: c7 44 24 04 02 00 00 movl $0x2,0x4(%esp) 804847d: 00 804847e: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048485: e8 8a ff ff ff call 8048414
Let's look at the 64-bit ubuntu operating system. 2 and 1 are not put into the stack at all, but in the registers esi and edi.
40056f: 48 89 e5 mov %rsp,%rbp test(1, 2); 400572: be 02 00 00 00 mov $0x2,%esi 400577: bf 01 00 00 00 mov $0x1,%edi 40057c: e8 ac ff ff ff callq 40052d
Let's take a look at the implementation of the 64-bit system test. We should first import edi into the stack and then esi into the stack. This is why the function looks like a stack from left to right.
40052d: 55 push %rbp 40052e: 48 89 e5 mov %rsp,%rbp 400531: 48 83 ec 10 sub $0x10,%rsp 400535: 89 7d fc mov %edi,-0x4(%rbp) 400538: 89 75 f8 mov %esi,-0x8(%rbp)