# >>>>>>>>>>>>> ELF FILE HEADER <<<<<<<<<<<<< # All numbers (except in names) are in base sixteen (hexadecimal) # 00 <- number of bytes listed so far 7F 45 4C 46 # 04 e_ident[EI_MAG]: ELF magic number 01 # 05 e_ident[EI_CLASS]: 1: 32-bit, 2: 64-bit 01 # 06 e_ident[EI_DATA]: 1: little-endian, 2: big-endian 01 # 07 e_ident[EI_VERSION]: ELF header version; must be 1 00 # 08 e_ident[EI_OSABI]: Target OS ABI; should be 0 00 # 09 e_ident[EI_ABIVERSION]: ABI version; 0 is ok for Linux 00 00 00 # 0C e_ident[EI_PAD]: unused, should be 0 00 00 00 00 # 10 02 00 # 12 e_type: object file type; 2: executable 03 00 # 14 e_machine: instruction set architecture; 3: x86, 3E: amd64 01 00 00 00 # 18 e_version: ELF identification version; must be 1 54 80 04 08 # 1C e_entry: memory address of entry point (where process starts) 34 00 00 00 # 20 e_phoff: file offset where program headers begin 00 00 00 00 # 24 e_shoff: file offset where section headers begin 00 00 00 00 # 28 e_flags: 0 for x86 34 00 # 2A e_ehsize: size of this header (34: 32-bit, 40: 64-bit) 20 00 # 2C e_phentsize: size of each program header (20: 32-bit, 38: 64-bit) 01 00 # 2E e_phnum: #program headers 28 00 # 30 e_shentsize: size of each section header (28: 32-bit, 40: 64-bit) 00 00 # 32 e_shnum: #section headers 00 00 # 34 e_shstrndx: index of section header containing section names # >>>>>>>>>>>>> ELF PROGRAM HEADER <<<<<<<<<<<<< 01 00 00 00 # 38 p_type: segment type; 1: loadable 5B 00 00 00 # 3C p_offset: file offset where segment begins 5B 80 04 08 # 40 p_vaddr: virtual address of segment in memory (x86: 08048054) 00 00 00 00 # 44 p_paddr: physical address of segment, unspecified by 386 supplement 59 00 00 00 # 48 p_filesz: size in bytes of the segment in the file image ############ 00 00 00 40 # 4C p_memsz: size in bytes of the segment in memory; p_filesz <= p_memsz 07 00 00 00 # 50 p_flags: segment-dependent flags (1: X, 2: W, 4: R) 00 10 00 00 # 54 p_align: 1000 for x86 # >>>>>>>>>>>>> PROGRAM SEGMENT <<<<<<<<<<<<< # Print the program # INTENTION INSTRUCTION OPCODE NOTE BD 02 00 00 00 # ebp <- 2 (min nums) mov r32, imm32 B8+rd id BE 00 80 04 08 # esi <- _ (start) mov r32, imm32 B8+rd id # 5E Byte: BB 10 00 00 00 # ebx <- 2^4 (hex) mov r32, imm32 B8+rd id 81 FE AF 80 04 08 # cmp esi, _ (end) cmp r/m32, imm32 81 /7 id 11 111 110 7D 3B # jge Exit jge rel8 7D cb 31 C0 # eax <- 0 xor r/m32, r32 31 /r 11 000 000 8A 06 # al <- [esi] mov r8, r/m8 8A /r 00 000 110 46 # esi++ inc r32 40+rd # 70 Num2buf: B9 00 00 00 09 # ecx <- obuf mov r32, imm32 B8+rd id C6 01 20 # [ecx] <- ' ' mov r/m8, imm8 C6 /0 ib 00 000 001 # Write the numerals (base EBX) of number EAX into memory just before ECX. # Let ECX0 denote the value of ECX before the routine, and ECX1 after. # After the routine, EDI is the len of the string, and ECX0 = ECX1 + EDI. 31 FF # edi <- 0 (count) xor r/m32, r32 31 /r 11 111 111 # 7A Numeral: # div r/m32: Unsigned divide EDX:EAX by r/m32, EAX = quot, EDX = rem 31 D2 # edx <- 0 xor r/m32, r32 31 /r 11 010 010 F7 F3 # divide by ebx div r/m32 F7 /6 11 110 011 80 FA 09 # cmp dl, 9 cmp r/m8, imm8 80 /7 ib 11 111 010 7E 03 # jle over next inst jle rel8 7E cb 80 C2 07 # dl += 'A' - A - '0' add r/m8, imm8 80 /0 ib 11 000 010 80 C2 30 # dl += '0' add r/m8, imm8 80 /0 ib 11 000 010 49 # ecx-- dec r32 48+rd 47 # edi++ inc r32 40+rd 88 11 # [ecx] <- dl mov r/m8, r8 88 /r 00 010 001 85 C0 # cmp eax, 0 test r/m32, r32 85 /r 11 000 000 75 E9 # jump Numeral if != jnz rel8 75 cb 39 EF # cmp edi, ebp cmp r/m32, r32 39 /r 11 101 111 7C E5 # jump Numeral if < jl rel8 7C cb 47 # edi++ inc r32 40+rd # 96 Write: B8 04 00 00 00 # eax <- 4 (write) mov r32, imm32 B8+rd id BB 01 00 00 00 # ebx <- 1 (stdout) mov r32, imm32 B8+rd id 89 FA # edx <- edi (count) mov r/m32, r32 89 /r 11 111 010 CD 80 # syscall int 80 CD ib EB B8 # jump Byte jmp rel8 EB cb # A6 Exit: B8 01 00 00 00 # eax <- 1 (exit) mov r32, imm32 B8+rd id 31 DB # ebx <- 0 (status) xor r/m32, r32 31 /r 11 011 011 CD 80 # syscall int 80 CD ib # AF