Adding Integers: i386#

Introduction#
In this section we will examine the disassembly of a simple C program that adds two integers. The program is compiled for the i386 architecture, which is a 32-bit architecture commonly used in older computers and embedded systems. The disassembly will help us understand how the C code translates into assembly instructions, and how these instructions are executed by the CPU.
The C Program#
#include <stdio.h>
int main(int argc, char * argv[])
{
int a, b, c;
a = 1;
b = 9;
c = a + b;
}
Compilation of the C Program to Produce Assembly Code and Object Code#
The C program is compiled using the GCC compiler with the -m32
flag to specify the i386 architecture. The -masm=intel
flag creates assembly code in the Intel format. The -S
flag generates assembly code, the -fverbose-asm flag includes C source code in the assembly code, and the -c
flag compiles the assembly code into an object file.
gcc --sysroot=/ -m32 -masm=intel -S -fverbose-asm add_int.c -o add_int.s
gcc --sysroot=/ -m32 -c add_int.s -o add_int.o
Viewing the Assembly Code#
The assembly code is in Intel syntax, which is commonly used for x86 assembly language.
.file "add_int.c"
.intel_syntax noprefix
# GNU C17 (conda-forge gcc 14.2.0-2) version 14.2.0 (x86_64-conda-linux-gnu)
# compiled by GNU C version 14.2.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# options passed: -m32 -masm=intel -mtune=generic -march=x86-64
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push ebp #
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp #,
.cfi_def_cfa_register 5
sub esp, 16 #,
call __x86.get_pc_thunk.ax #
add eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_ # tmp98,
# add_int.c:7: a = 1;
mov DWORD PTR -4[ebp], 1 # a,
# add_int.c:8: b = 9;
mov DWORD PTR -8[ebp], 9 # b,
# add_int.c:10: c = a + b;
mov edx, DWORD PTR -4[ebp] # tmp105, a
mov eax, DWORD PTR -8[ebp] # tmp106, b
add eax, edx # c_3, tmp105
mov DWORD PTR -12[ebp], eax # c, c_3
mov eax, 0 # _4,
# add_int.c:11: }
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
.globl __x86.get_pc_thunk.ax
.hidden __x86.get_pc_thunk.ax
.type __x86.get_pc_thunk.ax, @function
__x86.get_pc_thunk.ax:
.LFB1:
.cfi_startproc
mov eax, DWORD PTR [esp] #,
ret
.cfi_endproc
.LFE1:
.ident "GCC: (conda-forge gcc 14.2.0-2) 14.2.0"
.section .note.GNU-stack,"",@progbits
Explanation of the Assembly Code#
The attached file is an assembly code file (add_int.s
) generated from a C program (add_int.c
). It is written in Intel syntax and compiled for a 32-bit architecture (-m32
) using GCC 14.2.0. Below is a detailed explanation of the code:
Header Information#
File Metadata:
.file "add_int.c"
: Indicates that this assembly file was generated from the C source fileadd_int.c
.
Compiler Information:
The file was compiled using GCC 14.2.0 with the
-m32
flag for 32-bit architecture.Other flags include
-masm=intel
(Intel syntax),-mtune=generic
(generic CPU tuning), and-march=x86-64
(targeting x86-64 architecture).
GCC Heuristics:
Parameters like
ggc-min-expand
andggc-min-heapsize
are used for garbage collection optimization during compilation.
Main Function#
The main function (main
) is defined as a global symbol (.globl main
) and is marked as a function (.type main, @function
).
Prologue#
The prologue sets up the stack frame for the function:
push ebp
: Saves the base pointer of the previous stack frame.mov ebp, esp
: Sets the base pointer (ebp
) to the current stack pointer (esp
).sub esp, 16
: Allocates 16 bytes of space on the stack for local variables.
Global Offset Table Setup#
call __x86.get_pc_thunk.ax
: Calls a helper function to get the program counter (PC).add eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
: Adjusts the PC to point to the Global Offset Table (GOT), used for position-independent code.
Variable Initialization#
The C code initializes three variables (a
, b
, and c
):
mov DWORD PTR -4[ebp], 1
: Assigns1
toa
(stored at-4[ebp]
).mov DWORD PTR -8[ebp], 9
: Assigns9
tob
(stored at-8[ebp]
).
Addition Operation#
The C code computes c = a + b
:
mov edx, DWORD PTR -4[ebp]
: Loads the value ofa
intoedx
.mov eax, DWORD PTR -8[ebp]
: Loads the value ofb
intoeax
.add eax, edx
: Addsa
andb
, storing the result ineax
.mov DWORD PTR -12[ebp], eax
: Stores the result (c
) at-12[ebp]
.
Return Value#
mov eax, 0
: Sets the return value of the function to0
(standard forint main()
in C).
Epilogue#
The epilogue restores the stack frame:
leave
: Restores the previous base pointer and stack pointer.ret
: Returns control to the caller.
Helper Function: __x86.get_pc_thunk.ax
#
This function is used to retrieve the program counter (PC) for position-independent code:
mov eax, DWORD PTR [esp]
: Loads the return address (PC) from the stack intoeax
.ret
: Returns to the caller.
Other Sections#
.ident
Section:Contains metadata about the compiler version:
"GCC: (conda-forge gcc 14.2.0-2) 14.2.0"
.
.note.GNU-stack
Section:Indicates that the stack is not executable (a security feature).
Summary#
This assembly code represents a simple C program that initializes two integers (a = 1
and b = 9
), adds them (c = a + b
), and returns 0
. The code includes standard prologue and epilogue for stack management and uses a helper function for position-independent code.
Compilation to Produce Executable Code#
The object file is linked to create an executable file using the -o
flag.
/usr/bin/gcc -m32 add_int.o -o add_int_C_i386
Disassembly of the Executable Code#
The executable file is disassembled using the objdump
command with the -d
flag to display the disassembly.
objdump -x -D -s -t -Mintel add_int.o > objdump_of_dot_o.txt
objdump -x -D -s -t -Mintel add_int_C_i386 > objdump_of_dot_exe.txt
Explanation of the Switches used in the objdump
command:#
-x
: Displays all headers.-D
: Disassembles all sections.-s
: Displays the full contents of all sections.-t
: Displays the symbol table.-Mintel
: Specifies Intel syntax for disassembly.
Viewing the Object File Disassembly#
add_int.o: file format elf32-i386
add_int.o
architecture: i386, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000
Sections:
Idx Name Size VMA LMA File off Algn
0 .group 00000008 00000000 00000000 00000034 2**2
CONTENTS, READONLY, GROUP, LINK_ONCE_DISCARD
1 .text 00000030 00000000 00000000 0000003c 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 .data 00000000 00000000 00000000 0000006c 2**0
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00000000 00000000 00000000 0000006c 2**0
ALLOC
4 .text.__x86.get_pc_thunk.ax 00000004 00000000 00000000 0000006c 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 .comment 00000028 00000000 00000000 00000070 2**0
CONTENTS, READONLY
6 .note.GNU-stack 00000000 00000000 00000000 00000098 2**0
CONTENTS, READONLY
7 .note.gnu.property 00000028 00000000 00000000 00000098 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .eh_frame 0000004c 00000000 00000000 000000c0 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
00000000 l df *ABS* 00000000 add_int.c
00000000 l d .text 00000000 .text
00000000 l d .text.__x86.get_pc_thunk.ax 00000000 .text.__x86.get_pc_thunk.ax
00000000 g F .text 00000030 main
00000000 g F .text.__x86.get_pc_thunk.ax 00000000 .hidden __x86.get_pc_thunk.ax
00000000 *UND* 00000000 _GLOBAL_OFFSET_TABLE_
Contents of section .group:
0000 01000000 06000000 ........
Contents of section .text:
0000 5589e583 ec10e8fc ffffff05 01000000 U...............
0010 c745fc01 000000c7 45f80900 00008b55 .E......E......U
0020 fc8b45f8 01d08945 f4b80000 0000c9c3 ..E....E........
Contents of section .text.__x86.get_pc_thunk.ax:
0000 8b0424c3 ..$.
Contents of section .comment:
0000 00474343 3a202863 6f6e6461 2d666f72 .GCC: (conda-for
0010 67652067 63632031 342e322e 302d3229 ge gcc 14.2.0-2)
0020 2031342e 322e3000 14.2.0.
Contents of section .note.gnu.property:
0000 04000000 18000000 05000000 474e5500 ............GNU.
0010 020001c0 04000000 00000000 010001c0 ................
0020 04000000 01000000 ........
Contents of section .eh_frame:
0000 14000000 00000000 017a5200 017c0801 .........zR..|..
0010 1b0c0404 88010000 1c000000 1c000000 ................
0020 00000000 30000000 00410e08 8502420d ....0....A....B.
0030 056cc50c 04040000 10000000 3c000000 .l..........<...
0040 00000000 04000000 00000000 ............
Disassembly of section .group:
00000000 <.group>:
0: 01 00 add DWORD PTR [eax],eax
2: 00 00 add BYTE PTR [eax],al
4: 06 push es
5: 00 00 add BYTE PTR [eax],al
...
Disassembly of section .text:
00000000 <main>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 ec 10 sub esp,0x10
6: e8 fc ff ff ff call 7 <main+0x7>
7: R_386_PC32 __x86.get_pc_thunk.ax
b: 05 01 00 00 00 add eax,0x1
c: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
10: c7 45 fc 01 00 00 00 mov DWORD PTR [ebp-0x4],0x1
17: c7 45 f8 09 00 00 00 mov DWORD PTR [ebp-0x8],0x9
1e: 8b 55 fc mov edx,DWORD PTR [ebp-0x4]
21: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8]
24: 01 d0 add eax,edx
26: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
29: b8 00 00 00 00 mov eax,0x0
2e: c9 leave
2f: c3 ret
Disassembly of section .text.__x86.get_pc_thunk.ax:
00000000 <__x86.get_pc_thunk.ax>:
0: 8b 04 24 mov eax,DWORD PTR [esp]
3: c3 ret
Disassembly of section .comment:
00000000 <.comment>:
0: 00 47 43 add BYTE PTR [edi+0x43],al
3: 43 inc ebx
4: 3a 20 cmp ah,BYTE PTR [eax]
6: 28 63 6f sub BYTE PTR [ebx+0x6f],ah
9: 6e outs dx,BYTE PTR ds:[esi]
a: 64 61 fs popa
c: 2d 66 6f 72 67 sub eax,0x67726f66
11: 65 20 67 63 and BYTE PTR gs:[edi+0x63],ah
15: 63 20 arpl WORD PTR [eax],sp
17: 31 34 2e xor DWORD PTR [esi+ebp*1],esi
1a: 32 2e xor ch,BYTE PTR [esi]
1c: 30 2d 32 29 20 31 xor BYTE PTR ds:0x31202932,ch
22: 34 2e xor al,0x2e
24: 32 2e xor ch,BYTE PTR [esi]
26: 30 00 xor BYTE PTR [eax],al
Disassembly of section .note.gnu.property:
00000000 <.note.gnu.property>:
0: 04 00 add al,0x0
2: 00 00 add BYTE PTR [eax],al
4: 18 00 sbb BYTE PTR [eax],al
6: 00 00 add BYTE PTR [eax],al
8: 05 00 00 00 47 add eax,0x47000000
d: 4e dec esi
e: 55 push ebp
f: 00 02 add BYTE PTR [edx],al
11: 00 01 add BYTE PTR [ecx],al
13: c0 04 00 00 rol BYTE PTR [eax+eax*1],0x0
17: 00 00 add BYTE PTR [eax],al
19: 00 00 add BYTE PTR [eax],al
1b: 00 01 add BYTE PTR [ecx],al
1d: 00 01 add BYTE PTR [ecx],al
1f: c0 04 00 00 rol BYTE PTR [eax+eax*1],0x0
23: 00 01 add BYTE PTR [ecx],al
25: 00 00 add BYTE PTR [eax],al
...
Disassembly of section .eh_frame:
00000000 <.eh_frame>:
0: 14 00 adc al,0x0
2: 00 00 add BYTE PTR [eax],al
4: 00 00 add BYTE PTR [eax],al
6: 00 00 add BYTE PTR [eax],al
8: 01 7a 52 add DWORD PTR [edx+0x52],edi
b: 00 01 add BYTE PTR [ecx],al
d: 7c 08 jl 17 <.eh_frame+0x17>
f: 01 1b add DWORD PTR [ebx],ebx
11: 0c 04 or al,0x4
13: 04 88 add al,0x88
15: 01 00 add DWORD PTR [eax],eax
17: 00 1c 00 add BYTE PTR [eax+eax*1],bl
1a: 00 00 add BYTE PTR [eax],al
1c: 1c 00 sbb al,0x0
1e: 00 00 add BYTE PTR [eax],al
20: 00 00 add BYTE PTR [eax],al
20: R_386_PC32 .text
22: 00 00 add BYTE PTR [eax],al
24: 30 00 xor BYTE PTR [eax],al
26: 00 00 add BYTE PTR [eax],al
28: 00 41 0e add BYTE PTR [ecx+0xe],al
2b: 08 85 02 42 0d 05 or BYTE PTR [ebp+0x50d4202],al
31: 6c ins BYTE PTR es:[edi],dx
32: c5 0c 04 lds ecx,FWORD PTR [esp+eax*1]
35: 04 00 add al,0x0
37: 00 10 add BYTE PTR [eax],dl
39: 00 00 add BYTE PTR [eax],al
3b: 00 3c 00 add BYTE PTR [eax+eax*1],bh
3e: 00 00 add BYTE PTR [eax],al
40: 00 00 add BYTE PTR [eax],al
40: R_386_PC32 .text.__x86.get_pc_thunk.ax
42: 00 00 add BYTE PTR [eax],al
44: 04 00 add al,0x0
46: 00 00 add BYTE PTR [eax],al
48: 00 00 add BYTE PTR [eax],al
...
Explanation the Object File Disassembly#
This object code disassembly represents the compiled output of a C program for the i386 architecture. Below is an explanation of the key sections and their significance:
File Metadata#
add_int.o: file format elf32-i386
architecture: i386, flags 0x00000011:
HAS_RELOC, HAS_SYMS
start address 0x00000000
File format:
elf32-i386
indicates the ELF (Executable and Linkable Format) for the 32-bit i386 architecture.Flags:
HAS_RELOC
: The file contains relocation entries.HAS_SYMS
: The file contains a symbol table.
Start address: The starting address of the program is
0x00000000
.
Sections#
The disassembly lists various sections in the object file, each serving a specific purpose:
.group
Contains metadata for grouping related sections.
Flags:
CONTENTS, READONLY, GROUP, LINK_ONCE_DISCARD
.
.text
Contains the executable code (instructions).
Flags:
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
.
.data
Contains initialized global and static variables.
Flags:
CONTENTS, ALLOC, LOAD, DATA
.
.bss
Contains uninitialized global and static variables.
Flags:
ALLOC
.
.text.__x86.get_pc_thunk.ax
Contains helper code for position-independent code (PIC).
Flags:
CONTENTS, ALLOC, LOAD, READONLY, CODE
.
.comment
Contains compiler version information.
Flags:
CONTENTS, READONLY
.
.note.GNU-stack
Marks the stack as non-executable for security purposes.
Flags:
CONTENTS, READONLY
.
.eh_frame
Contains exception handling information for stack unwinding.
Flags:
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
.
Symbol Table#
The symbol table lists symbols (functions, variables, and sections) in the object file:
00000000 g F .text 00000030 main
00000000 g F .text.__x86.get_pc_thunk.ax 00000000 .hidden __x86.get_pc_thunk.ax
00000000 *UND* 00000000 _GLOBAL_OFFSET_TABLE_
main
: The main function is defined in the.text
section and has a size of0x30
bytes.__x86.get_pc_thunk.ax
: A helper function for position-independent code._GLOBAL_OFFSET_TABLE_
: An undefined symbol used for dynamic linking.
Disassembly of .text
Section#
This section contains the main function’s instructions:
00000000 <main>:
0: 55 push ebp
1: 89 e5 mov ebp,esp
3: 83 ec 10 sub esp,0x10
6: e8 fc ff ff ff call 7 <main+0x7>
7: R_386_PC32 __x86.get_pc_thunk.ax
b: 05 01 00 00 00 add eax,0x1
c: R_386_GOTPC _GLOBAL_OFFSET_TABLE_
10: c7 45 f4 01 00 00 00 mov DWORD PTR [ebp-0xc],0x1
17: c7 45 f8 09 00 00 00 mov DWORD PTR [ebp-0x8],0x9
1e: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]
21: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8]
24: 01 d0 add eax,edx
26: 89 45 fc mov DWORD PTR [ebp-0x4],eax
29: b8 00 00 00 00 mov eax,0x0
2e: c9 leave
2f: c3 ret
Prologue:
push ebp
: Saves the base pointer of the previous stack frame.mov ebp, esp
: Sets up the current stack frame.sub esp, 0x10
: Allocates 16 bytes for local variables.
Position-Independent Code Setup:
call __x86.get_pc_thunk.ax
: Calls a helper function to get the program counter.add eax, _GLOBAL_OFFSET_TABLE_
: Adjusts the program counter for the Global Offset Table (GOT).
Variable Initialization:
mov DWORD PTR [ebp-0xc], 0x1
: Stores1
in the local variable at-0xc
.mov DWORD PTR [ebp-0x8], 0x9
: Stores9
in the local variable at-0x8
.
Addition:
mov edx, DWORD PTR [ebp-0xc]
: Loads the first variable (1
) intoedx
.mov eax, DWORD PTR [ebp-0x8]
: Loads the second variable (9
) intoeax
.add eax, edx
: Addsedx
toeax
(result:10
).mov DWORD PTR [ebp-0x4], eax
: Stores the result (10
) in the local variable at-0x4
.
Return Value:
mov eax, 0x0
: Sets the return value to0
.leave
: Restores the previous stack frame.ret
: Returns control to the caller.
Disassembly of .text.__x86.get_pc_thunk.ax
#
This helper function retrieves the program counter for position-independent code:
00000000 <__x86.get_pc_thunk.ax>:
0: 8b 04 24 mov eax,DWORD PTR [esp]
3: c3 ret
mov eax, DWORD PTR [esp]
: Loads the return address (program counter) intoeax
.ret
: Returns to the caller.
Disassembly of .comment
#
Contains metadata about the compiler:
00000000 <.comment>:
0: 00 47 43 add BYTE PTR [edi+0x43],al
...
This section is not executable and contains the string
GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0
.
Disassembly of .eh_frame
#
Contains exception handling information for stack unwinding:
00000000 <.eh_frame>:
0: 14 00 adc al,0x0
...
This section is used by the runtime for exception handling and debugging.
Summary#
This object file disassembly shows:
Code Structure: The
.text
section contains the main function and helper code for position-independent execution.Relocation: The GOT setup ensures compatibility with dynamically linked libraries.
Metadata: Sections like
.comment
and.eh_frame
provide additional information for debugging and exception handling.
Project Code on GitHub#
Project code and resources can be found on my GitHub repository:
GitHub