Method 1: Use gcc
There are four steps for GCC Compilation: Pre-compilation, and connection.
Use the-s compilation Option
Gcc-s test. c
The test. s file will be generated in the current directory, which is the corresponding Assembler
Method 2: Use GDB
First, use the-G compilation option during compilation.
Gcc-G./test. C-o./test
Run GDB.
GDB./test -- (Executable File)
Use disassemble + frame (FRAME) in GDB to view the assembly code of the corresponding code segment.
Frame is usually a function name.
Method 3: Use objdump
Command is
Objdump-d test. O -- (target file)
Or
Objdump-d test -- (Executable File)
An disassembly code explanation:
(This example uses the GCC Assembly format, which is called gas (GNU Compiler, GNU Compiler ))
The C language code is as follows:
------ Test. c -------
# Include <stdio. h> <br/> # include <unistd. h> <br/> int static_var = 5; <br/> int <br/> fun_ret_int (int A, int B, register int C) <br/>{< br/> int d = 1; <br/> return A + B + C + D; <br/>}< br/> void fun () <br/>{< br/> int I1, I2, I3, I4, I5, I6, i7, i8, I9, I10; <br/> I1 = 1; i2 = 3; I3 = 5; I4 = 7; I5 = 9; I6 = 11; i7 = 13; i8 = 15; I9 = 17; I10 = 19; <br/> int I; <br/> for (I = 11; I <20; ++ I); <br/> I2 = fun_ret_int (1, 2, i1); <br/>}< br/> int main (INT argc, char * argv []) <br/>{< br/> int I = 1; <br/> int B = 2; <br/> argc = 3; <br/> char ** A = argv; <br/> fun (); <br/> return 0; <br/>}< br/>
Compile now:
GCC test. C-o Test
Disassembly:
Objdump-D Test
Part of my code is as follows:
08048394 <fun_ret_int >:< br/> 8048394: 55 push % EBP <br/> 8048395: 89 E5 mov % ESP, % EBP <br/> 8048397: 83 EC 10 sub $0x10, % ESP <br/> 804839a: 8B 4D 10 mov 0x10 (% EBP), % ECx <br/> 804839d: c7 45 FC 01 00 00 00 movl $0x1,-0x4 (% EBP) <br/> 80483a4: 8B 45 0C mov 0xc (% EBP ), % eax <br/> 80483a7: 8B 55 08 mov 0x8 (% EBP), % edX <br/> 80483aa: 8d 04 02 LEA (% edX, % eax, 1), % eax <br/> 80483ad: 01 C8 add % ECx, % eax <br/> 80483af: 03 45 FC add-0x4 (% EBP ), % eax <br/> 80483b2: C9 leave <br/> 80483b3: C3 RET <br/> 080483b4 <fun >:< br/> 80483b4: 55 push % EBP <br/> 80483b5: 89 E5 mov % ESP, % EBP <br/> 80483b7: 83 EC 3C sub $ 0x3c, % ESP <br/> 80483ba: c7 45 FC 01 00 00 00 movl $0x1,-0x4 (% EBP) <br/> 80483c1: C7 45 F8 03 00 00 00 movl $0x3, -0x8 (% EBP) <br/> 80483c8: C7 45 F4 05 00 00 00 movl $0x5,-0xc (% EBP) <br/> 80483cf: c7 45 F0 07 00 00 00 movl $0x7,-0x10 (% EBP) <br/> 80483d6: C7 45 EC 09 00 00 00 movl $0x9, -0x14 (% EBP) <br/> 80483dd: C7 45 E8 0b 00 00 00 movl $0xb,-0x18 (% EBP) <br/> 80483e4: c7 45 E4 0d 00 00 00 movl $ 0xd,-0x1c (% EBP) <br/> 80483eb: C7 45 E0 0f 00 00 00 movl $ 0xf, -0x20 (% EBP) <br/> 80483f2: C7 45 DC 11 00 00 00 movl $0x11,-0x24 (% EBP) <br/> 80483f9: C7 45 D8 13 00 00 00 movl $0x13,-0x28 (% EBP) <br/> 8048400: c7 45 D4 01 00 00 00 movl $0x1,-0x2c (% EBP) <br/> 8048407: C7 45 D0 0b 00 00 00 movl $ 0xb, -0x30 (% EBP) <br/> 804840e: EB 04 JMP 8048414 <fun + 0x60> <br/> 8048410: 83 45 D0 01 addl $0x1,-0x30 (% EBP) <br/> 8048414: 83 7d D0 13 CMPL $0x13, -0x30 (% EBP) <br/> 8048418: 7E F6 jle 8048410 <fun + 0x5c> <br/> 804841a: 8b 45 FC mov-0x4 (% EBP), % eax <br/> 804841d: 89 44 24 08 mov % eax, 0x8 (% ESP) <br/> 8048421: C7 44 24 04 02 00 00 movl $0x8048428x4 (% ESP) <br/> 8048429: 00 <br/>: c7 04 24 01 00 00 00 movl $0x1, (% ESP) <br/> 8048430: E8 5f FF call 8048394 <fun_ret_int> <br/> 8048435: 89 45 F8 mov % eax,-0x8 (% EBP) <br/> 8048438: C9 leave <br/> 8048439: C3 RET <br/> 0804843a <main>: <br/> 804843a: 55 push % EBP <br/> 804843b: 89 E5 mov % ESP, % EBP <br/> 804843d: 83 EC 10 sub $0x10, % ESP <br/> 8048440: C7 45 FC 01 00 00 00 movl $0x1,-0x4 (% EBP) <br/> 8048447: c7 45 F8 02 00 00 00 movl $0x2,-0x8 (% EBP) <br/> 804844e: c7 45 08 03 00 00 00 movl $0x3, 0x8 (% EBP) <br/> 8048455: 8B 45 0C mov 0xc (% EBP ), % eax <br/> 8048458: 89 45 F4 mov % eax,-0xc (% EBP) <br/> 804845b: e8 54 FF call 80483b4 <fun> <br/> 8048460: B8 00 00 00 00 mov $0x0, % eax <br/> 8048465: c9 leave <br/> 8048466: C3 RET <br/> 8048467: 90 NOP <br/> 8048468: 90 NOP <br/> 8048469: 90 NOP <br/> 804846a: 90 NOP <br/> 804846b: 90 NOP <br/> 804846c: 90 NOP <br/> 804846d: 90 NOP <br/> 804846e: 90 NOP <br/> 804846f: 90 NOP
Now try to analyze some of the statements:
At the beginning of each function is:
Push % EBP <br/> mov % ESP, % EBP <br/> sub $ ***, % ESP
% EBP --- indicates the frame register, which is the base address register of the function in the function, pointing to the stack bottom (frame bottom) of a function ).
% ESP --- is the stack register, which is equivalent to the base register of the entire program, always pointing to the top of the stack.
Push --- import stack operation.
MoV --- move
Sub --- Subtraction
In the first sentence, push % EBP means % EBP is put into the stack. At this time, % EBP stores the starting address of the frame of the previous function, that is, the address of the call to this function.
Store % EBP on the stack for return.
In the second sentence mov % ESP, % EBP means to assign % ESP to % EBP, % ESP stores the top stack of the current program, that is, the starting address of the memory occupied by the function.
Assign % ESP to % EBP, and set % EBP to the frame start address of the current function.
In the third sentence, sub $ ***, % ESP will not appear in every program. You can try it. If a function does not have any local variables, then this statement will be decompiled.
No. This sentence means to subtract % esp from a number. We know that stack space is developed by high to the end, so % ESP ++, equivalent to % ESP = % esp-1. Because a new function is called and the function has local variables, the stack space becomes larger. Therefore, you need to expand the stack space, that is, modify % ESP and point it to a lower address. How much does % ESP subtract? This depends on the space occupied by the function, the local variables in the function, and the function parameters that will be called. It does not calculate the space occupied by its parameters. The space occupied by its parameters must be included in the function that calls it.
Next let's take a look at the parameter pressure stack sequence;
Statement in function fun:
I2 = fun_ret_int (1, 2, i1 );
The corresponding compilation is as follows:
804841a: 8B 45 FC mov-0x4 (% EBP), % eax <br/> 804841d: 89 44 24 08 mov % eax, 0x8 (% ESP) <br/> 8048421: C7 44 24 04 02 00 00 movl $0x8048428x4 (% ESP) <br/> 8048429: 00 <br/>: c7 04 24 01 00 00 00 movl $0x1, (% ESP) <br/> 8048430: E8 5f FF call 8048394 <fun_ret_int>
From this Assembly, we can see that the order of function parameters in the stack is from left to right.
Mov-0x4 (% EBP), % eax puts I1 in % eax register
MoV % eax, 0x8 (% ESP) is to press % eax to stack, so this sentence is to put I1 at the distance % ESP is 8 bytes, that is, 8 ~ 12byte stores an I1 (INT)
Movl $0x2, 0x4 (% ESP): % ESP 4 ~ 8 byte stores 2 (INT)
Movl $0x1, (% ESP) 0 to % ESP ~ 4 byte stores 1 (INT)
Because the stack is from high to low, and % ESP always points to the top of the stack. Therefore, the order of inbound and outbound stack access is I1, 2, and 1. The order of parameters of the fun function in the C file is the opposite.
What are the advantages of stack from right to left? First, because the stack is Filo, the first parameter is closer to % esp when the stack is in the opposite direction. It is convenient to take parameters every time. You do not need to calculate the space occupied by all parameters and then obtain them. Second, when too many parameters are passed, each time they are calculated from the top of the stack, the parameters at the appropriate position can be ignored.