Dividing Integers: i386#

Introduction#
In this section we will examine the disassembly of a simple C program that divides 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 = 10;
b = 5;
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 div_int.c -o div_int.s
gcc --sysroot=/ -m32 -c div_int.s -o div_int.o
Viewing the Assembly Code#
The assembly code is in Intel syntax, which is commonly used for x86 assembly language.
.file "div_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,
# div_int.c:7: a = 10;
mov DWORD PTR -4[ebp], 10 # a,
# div_int.c:8: b = 5;
mov DWORD PTR -8[ebp], 5 # b,
# div_int.c:10: c = a / b;
mov eax, DWORD PTR -4[ebp] # tmp104, a
cdq
idiv DWORD PTR -8[ebp] # b
mov DWORD PTR -12[ebp], eax # c, c_3
mov eax, 0 # _4,
# div_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 code is an assembly file (div_int.s
) generated from a C program (div_int.c
) using the GCC compiler. It is written in Intel syntax and targets the x86 architecture in 32-bit mode (-m32
). Below is a detailed explanation of the code:
Header Information#
.file "div_int.c"
Indicates that this assembly file was generated from the source filediv_int.c
..intel_syntax noprefix
Specifies that the assembly code uses Intel syntax (as opposed to AT&T syntax) and does not require prefixes like%
for registers.Compiler Metadata
The code was compiled using GCC version 14.2.0.
It includes information about the compiler’s configuration, such as GMP, MPFR, and MPC versions, as well as the target architecture (
x86_64-conda-linux-gnu
).The options used during compilation include:
-m32
: Generate 32-bit code.-masm=intel
: Use Intel assembly syntax.-mtune=generic
: Optimize for a generic x86 processor.-march=x86-64
: Target the x86-64 architecture.
Main Function#
The main function is defined as a global symbol (.globl main
) and is marked as a function (.type main, @function
). It begins at the label main:
.
Prologue#
The prologue sets up the stack frame for the function:
push ebp
Saves the base pointer (ebp
) of the caller function onto the stack.mov ebp, esp
Sets the current base pointer (ebp
) to the value of the stack pointer (esp
), establishing a new stack frame.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) value.add eax, OFFSET FLAT:_GLOBAL_OFFSET_TABLE_
Adjusts the PC value to point to the Global Offset Table (GOT), which is used for position-independent code.
Variable Initialization#
The C code initializes three variables: a
, b
, and c
. These are represented as local variables on the stack:
mov DWORD PTR -4[ebp], 10
Stores the value10
(fora
) at the memory location-4[ebp]
.mov DWORD PTR -8[ebp], 5
Stores the value5
(forb
) at the memory location-8[ebp]
.
Division Operation#
The C code performs the division c = a / b
:
mov eax, DWORD PTR -4[ebp]
Loads the value ofa
into theeax
register.cdq
Converts the value ineax
to a 64-bit value by sign-extending it into theedx:eax
pair. This is required for signed division.idiv DWORD PTR -8[ebp]
Performs signed integer division ofedx:eax
by the value ofb
. The quotient is stored ineax
, and the remainder is stored inedx
.mov DWORD PTR -12[ebp], eax
Stores the result of the division (the quotient,c
) into the memory location-12[ebp]
.
Return Value#
mov eax, 0
Sets the return value of the function to0
(as per the C standard forint main()
).
Epilogue#
The epilogue restores the stack frame and returns control to the caller:
leave
Restores the stack pointer (
esp
) to the base pointer (ebp
).Pops the old base pointer from the stack into
ebp
.
ret
Returns control to the caller by popping the return address from the stack.
Helper Function: __x86.get_pc_thunk.ax
#
This function is used to retrieve the program counter (PC) value for position-independent code:
mov eax, DWORD PTR [esp]
Loads the return address (stored at the top of the stack) into theeax
register.ret
Returns control to the caller.
Additional Sections#
.ident
Contains a string identifying the compiler version used to generate the assembly code..section .note.GNU-stack
Marks the stack as non-executable, which is a security feature.
Summary#
This assembly code implements a simple C program that initializes two integers (a = 10
and b = 5
), performs integer division (c = a / b
), and returns 0
. The code is optimized for 32-bit x86 architecture and includes standard prologue and epilogue for stack management.
Compilation to Produce Executable Code#
The object file is linked to create an executable file using the -o
flag.
/usr/bin/gcc -m32 div_int.o -o div_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 div_int.o > objdump_of_dot_o.txt
objdump -x -D -s -t -Mintel div_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#
div_int.o: file format elf32-i386
div_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 0000002f 00000000 00000000 0000003c 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 .data 00000000 00000000 00000000 0000006b 2**0
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00000000 00000000 00000000 0000006b 2**0
ALLOC
4 .text.__x86.get_pc_thunk.ax 00000004 00000000 00000000 0000006b 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 .comment 00000028 00000000 00000000 0000006f 2**0
CONTENTS, READONLY
6 .note.GNU-stack 00000000 00000000 00000000 00000097 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 div_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 0000002f 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 c745fc0a 000000c7 45f80500 00008b45 .E......E......E
0020 fc99f77d f88945f4 b8000000 00c9c3 ...}..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 2f000000 00410e08 8502420d ..../....A....B.
0030 056bc50c 04040000 10000000 3c000000 .k..........<...
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 0a 00 00 00 mov DWORD PTR [ebp-0x4],0xa
17: c7 45 f8 05 00 00 00 mov DWORD PTR [ebp-0x8],0x5
1e: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
21: 99 cdq
22: f7 7d f8 idiv DWORD PTR [ebp-0x8]
25: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
28: b8 00 00 00 00 mov eax,0x0
2d: c9 leave
2e: 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: 2f das
25: 00 00 add BYTE PTR [eax],al
27: 00 00 add BYTE PTR [eax],al
29: 41 inc ecx
2a: 0e push cs
2b: 08 85 02 42 0d 05 or BYTE PTR [ebp+0x50d4202],al
31: 6b c5 0c imul eax,ebp,0xc
34: 04 04 add al,0x4
36: 00 00 add BYTE PTR [eax],al
38: 10 00 adc BYTE PTR [eax],al
3a: 00 00 add BYTE PTR [eax],al
3c: 3c 00 cmp al,0x0
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#
The attached file is the output of the objdump
tool, which is used to analyze binary files. Specifically, this is the disassembly of an object file named div_int.o
compiled for the elf32-i386
architecture. Below is a detailed explanation of the file’s contents:
File Header#
The first few lines provide metadata about the object file:
File Format:
elf32-i386
indicates the file is in the ELF (Executable and Linkable Format) for the 32-bit Intel x86 architecture.Architecture:
i386
specifies the target CPU architecture.Flags:
0x00000011
indicates the file has relocation entries (HAS_RELOC
) and symbols (HAS_SYMS
).Start Address:
0x00000000
is the entry point address (not relevant for object files, as they are not executable).
Sections#
The object file is divided into sections, each serving a specific purpose. The table lists the sections with their attributes:
.group:
Size:
0x08
bytes.Purpose: Groups related sections for optimization (e.g.,
LINK_ONCE_DISCARD
ensures duplicate sections are discarded during linking).Attributes:
CONTENTS, READONLY, GROUP
.
.text:
Size:
0x2f
bytes.Purpose: Contains executable code (machine instructions).
Attributes:
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
.
.data:
Size:
0x00
bytes.Purpose: Stores initialized global and static variables.
Attributes:
CONTENTS, ALLOC, LOAD, DATA
.
.bss:
Size:
0x00
bytes.Purpose: Stores uninitialized global and static variables.
Attributes:
ALLOC
.
.text.__x86.get_pc_thunk.ax:
Size:
0x04
bytes.Purpose: Contains a helper function for position-independent code (PIC).
Attributes:
CONTENTS, ALLOC, LOAD, READONLY, CODE
.
.comment:
Size:
0x28
bytes.Purpose: Stores compiler version information.
Attributes:
CONTENTS, READONLY
.
.note.GNU-stack:
Size:
0x00
bytes.Purpose: Marks the stack as non-executable (security feature).
Attributes:
CONTENTS, READONLY
.
.note.gnu.property:
Size:
0x28
bytes.Purpose: Stores metadata about the binary (e.g., ABI compatibility).
Attributes:
CONTENTS, ALLOC, LOAD, READONLY, DATA
.
.eh_frame:
Size:
0x4c
bytes.Purpose: Stores exception handling information (used for stack unwinding).
Attributes:
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
.
Symbol Table#
The symbol table lists symbols (functions, variables, etc.) defined or referenced in the object file:
main
:Location:
.text
section.Size:
0x2f
bytes.Type: Global function (
g F
).
__x86.get_pc_thunk.ax
:Location:
.text.__x86.get_pc_thunk.ax
section.Size:
0x00
bytes.Type: Hidden function (
.hidden
).
_GLOBAL_OFFSET_TABLE_
:Location: Undefined (
*UND*
).Purpose: Used for position-independent code (PIC).
Section Contents#
The contents of each section are displayed in hexadecimal and disassembled into assembly instructions.
.group#
Contains metadata for grouping sections.
.text#
Contains the implementation of the
main
function: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> b: 05 01 00 00 00 add eax,0x1 10: c7 45 fc 0a 00 00 00 mov DWORD PTR [ebp-0x4],0xa 17: c7 45 f8 05 00 00 00 mov DWORD PTR [ebp-0x8],0x5 1e: 8b 45 fc mov eax,DWORD PTR [ebp-0x4] 21: 99 cdq 22: f7 7d f8 idiv DWORD PTR [ebp-0x8] 25: 89 45 f4 mov DWORD PTR [ebp-0xc],eax 28: b8 00 00 00 00 mov eax,0x0 2d: c9 leave 2e: c3 ret
This function performs integer division:
Stores
10
and5
in local variables.Divides
10
by5
using theidiv
instruction.Stores the result in another local variable.
.text.__x86.get_pc_thunk.ax#
Contains a helper function for position-independent code:
00000000 <__x86.get_pc_thunk.ax>: 0: 8b 04 24 mov eax,DWORD PTR [esp] 3: c3 ret
.comment#
Contains the compiler version:
GCC: (conda-forge gcc 14.2.0-2) 14.2.0
.note.gnu.property#
Contains metadata about the binary.
.eh_frame#
Contains exception handling information.
Relocation Entries#
Relocation entries are present in the .text
section:
R_386_PC32
: Relocation for position-independent code.R_386_GOTPC
: Relocation for the Global Offset Table (GOT).
Disassembly#
The disassembly of each section shows the machine instructions and their corresponding assembly code. For example:
main
function:Sets up the stack frame.
Performs integer division.
Cleans up and returns.
__x86.get_pc_thunk.ax
:Retrieves the program counter for position-independent code.
Summary#
This object file (div_int.o
) contains a simple program that performs integer division. It is compiled for the 32-bit x86 architecture and includes metadata, code, and relocation entries. The main
function divides two integers (10 / 5
) and stores the result. The file also includes helper functions and metadata for position-independent code and exception handling.
Project Code on GitHub#
Project code and resources can be found on my GitHub repository:
GitHub