Hello World: C, 어셈블리, 오브젝트 파일 그리고 실행파일

2022. 12. 26. 19:40프로그래밍

728x90

https://resources.infosecinstitute.com/topic/hello-world-c-assembly-object-file-and-executable/

 

Hello world: C, assembly, object file and executable | Infosec Resources

Summary: In this article we'll take a look at the C program that prints "Hello World!" to the screen, which we'll assemble and compile. Then we'll compare

resources.infosecinstitute.com

 

 

시작해보기

어셈블리로 짜고 컴파일해서 Hello World 를 스크린에 찍는 단순한 프로그램을 만드는 일입니다.

하지만 그 이면에는 무슨일이 일어나고 있는 것일까요?

하나의 사슬같은 관계로 이를 살펴보려고 합니다. C코드에서 어셈블리코드로 다시 오브젝트 파일로 그리고 실행 파일까지의 사슬을 만들어보기로 합니다.

Hello World 프로그램 : 어셈블리

그럼 우선 Hello World 프로그램을 만들어보기로 합시다:

#include <stdio.h>

int main() {
	printf("Hello World!");
	return 0;
}
 

그냥 단순한 프로그램 입니다. 그럼 GCC를 사용해서 어셈블리 코드를 얻어보기로 할까요?

여기서 우리는 어셈블 코드를 얻기 위해서 -S 옵션을 사용합니다.

(어셈블리 인스트럭션 생성) 여기서 masm 코드를 얻는 것은 그리 어렵지 않습니다.

단지 -masm-intel 옵션만 우리의 GCC에게 던져넣기만 하면 되니까요.

만약 64비트 환경으로 만들어야 할 경우를 대비해서 -m32 옵션으로 32비트 환경을 완성 할 수 있을 것입니다.

그럼 이렇게해서 다음과 같은 gcc 명령으로 컴파일 하게 될 것입니다.

gcc -m32 -masm=intel -S hello.c -o hello.s
 

32비트 환경으로 만들어 진 hello.s 파일에는 다음과 같은 어셈블리 인스트럭션들이 담겨져 있을 것입니다.

.file “hello.c”
.intel_syntax noprefix
.section .rodata
.LC0:
.string “Hello World!”
.text
.globl main
.type main, @function
main:
push ebp
mov ebp, esp
and esp, -16
sub esp, 16
mov eax, OFFSET FLAT:.LC0
mov DWORD PTR [esp], eax
call printf
mov eax, 0
leave
ret
.size main, .-main
.ident “GCC: (Gentoo 4.5.4 p1.0, pie-0.4.7) 4.5.4″
.section .note.GNU-stack,””,@progbits
 
  • ​file 지시자는 일반적으로 디버거에서 사용하는 원본 소스 파일 이름을 가리키는 지시자입니다.
  • .intel_syntax 라인은 우리가 AT&T 문법이 아닌 intel 문법의 어셈블리를 사용한다는 한정어이다.
  • .rodata 섹션을 정의하는 데 이 섹션은 읽기전용 데이터 변수 선언부 입니다.
    • 여기의 경우에는 그냥 LC0 변수에 의해 접근 할 수 있는“Hello World!” NULL 분리 문자열이 이 섹션에 전부 입니다.
  • .text 섹션은 프로그램 실행 코드를 만들 때 사용 되는 부분입니다.

 

  • .type main,@function 인스트럭션 : 첫 번째 할 일은메인 함수를() 정의하는 일이며, 전 코드에 걸쳐 접근 가능한 코드를(.globl main 인스트럭션) 얻을 수 있습니다.
  • main: 라벨에서 ret 라벨까지가 실제 프로그램 코드가 되겠습니다.

 

코드는 처음에 레지스터 EBP의 값을 스택에 넣으므로써(push) 스택의 값을 초기화 하고 레지스터 EBP의 값을 EBP 레지스터로 옮깁니다.

and  esp, -16
 

위 코드는 만약 스택포인터의 주소가 16 바이트의 배수인 경우에 성능을 향상 시키기 위한 최적화 구문이며, 이 인스트럭션은 이에 대한 디폴트이며 gcc는 최적화 옵션인 -O2를 사용하게 됩니다.

그리고 지역변수들을 위해서 현재 ESP 스택 포인터 레지스터에서 16 바이트를 빼줍니다.

 

다음으로 LC0 의 주소에서 (“Hello World!” 문자열) eax 레지스터로 읽어 들이면 스택의 최상위로 옮겨지는 것입니다.

이 스택은 최초 부분이며, 이 후에 printf 문이 호출되면서 파라메터로 전달 됩니다.

  • printf 함수는 스크린에 문자열을 표출하고 스택과 리턴을 책임지고 있는 호출자에게 반환 됩니다.
  • .size 인스트럭션은 메인 함수의 크기를 설정 합니다.
  • -main은 오브텍트 파일에 쓰여질 main 함수의 정확한 크기를 가지고 있습니다.
  • .ident 인스트럭션은 어떤 컴파일러를 사용해서 컴파일하고 실행하였는지에 대한 정보 문자열인”GCC: (Gentoo 4.5.4 p1.0, pie-0.4.7) 4.5.4″문자열을 오브젝트 파일에 저장하기 위한 인스트럭션이 되겠습니다.

 

Hello World 프로그램 : 오브젝트 파일

여기까지 우리는 C 소스코드로 부터 직접적으로 어셈블리 코드를 얻는 방법에 대해서 접근 해보았습니다. 그렇지만 실제 어셈블러와 링커 없이 우리는 이 파일을 실행하지 못합니다. 오브젝트 파일에 실행을 조합해 넣기 위해서는 gcc 컴파일러에 소스코드를 올려놓고, 컴파일 -c 옵션을 사용하겠지만 이 옵션으로 링크 시키지는 못합니다.

그래서 이 모든 일이 가능하도록 어셈블리 코드에서 오브젝트 파일을 얻기위해서 다음 명령어를 수행해 봅시다.

gcc -m32 -masm=intel -c hello.s -o hello.o
file hello.o
 

출력:

hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
 

hello.o는 아직 링크되지 못한 실행가능한 ELF 32-bit 오브젝트 파일임을 나타내고 있습니다.

만약 이 파일을 실행 하려 한다면 다음과 같은 실패 메시지를 보게 되겠죠.

chmod +x hello.o
./hello.o
 

출력:

bash: ./hello.o: cannot execute binary file
 

우리는 다음 readelf 프로그램을 사용해서 오브젝트 파일의 내용을 확인 해 볼 수 있습니다.

readelf -a hello.o
 

출력:

ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2’s complement, little endian
Version: 1 (current)
OS/ABI: UNIX – System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 224 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 11
Section header string table index: 8
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 00001d 00 AX 0 0 4
[ 2] .rel.text REL 00000000 000350 000010 08 9 1 4
[ 3] .data PROGBITS 00000000 000054 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000054 000000 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000054 00000d 00 A 0 0 1
[ 6] .comment PROGBITS 00000000 000061 00002b 01 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 00000000 00008c 000000 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 00008c 000051 00 0 0 1
[ 9] .symtab SYMTAB 00000000 000298 0000a0 10 10 8 4
[10] .strtab STRTAB 00000000 000338 000015 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
Relocation section ‘.rel.text’ at offset 0x350 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0000000a 00000501 R_386_32 00000000 .rodata
00000012 00000902 R_386_PC32 00000000 printf
There are no unwind sections in this file.
Symbol table ‘.symtab’ contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS hello.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 7
7: 00000000 0 SECTION LOCAL DEFAULT 6
8: 00000000 29 FUNC GLOBAL DEFAULT 1 main
9: 00000000 0 NOTYPE GLOBAL DEFAULT UND printf
No version information found in this file.
 

​우리는 이 ELF 오브젝트 파일이 11개의 섹션 헤더들을 가지고 있다는 것을 볼 수가 있습니다.

[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 00001d 00 AX 0 0 4
[ 2] .rel.text REL 00000000 000350 000010 08 9 1 4
[ 3] .data PROGBITS 00000000 000054 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000054 000000 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000054 00000d 00 A 0 0 1
[ 6] .comment PROGBITS 00000000 000061 00002b 01 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 00000000 00008c 000000 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 00008c 000051 00 0 0 1
[ 9] .symtab SYMTAB 00000000 000298 0000a0 10 10 8 4
[10] .strtab STRTAB 00000000 000338 000015 00 0 0 1
 

첫번째 섹션 헤더는 NULL입니다.

두번째 섹션 헤더는 프로그램의 실행가능 인스트럭션을 가진.text 섹션입니다.

.rel.text 헤더는 .text 섹션의 재배치 정보를 가지고 있습니다. 이 재배치(relocation) 항목들은 우리의 프로그램 인스트럭션이 외부함수를 호출 할때 노출되어 있어야하며, 이 함수 포인터들은 프로그램 실행 시에 업데이트 되어야만 합니다.

 

위에서 보면 .rel.text 는 두개의 재배치 항목들을 가지고 있는 데 .rodata 와 printf가 그것입니다.

.data 섹션 헤더는 초기화된 데이터를 가지고 있으며

.bss 섹션헤더는 프로그램에서 사용하는 초기화 되지 않은 데이터를 가지는 영역입니다.

.rodata 는 프로그램에서 사용하는 읽기전용 데이터를 가지고 있다. 이 데이터가 바로 우리의 “Hello World!” 가 저장되어 있는 섹션이 되겠습니다.

.comment 섹션 헤더는 버전 컨트롤 정보를 가지며,

.note.GNU-stack 섹션 헤더는 여기서는 언급하지 않을 몇가지 부가정보를 가지고 있습니다.

.shstrtab 섹션 헤더는 .strtab 섹션 문자열을 가지고 .symtab 은 심볼 테이블을 가지는 반면, 섹션의이름을 가집니다.

 

여기서 우리가 바로 알 수 있는 점은 .rodata와 .text 섹션이 실제적인 어셉블리 코드를 나타내고 있다는 것이지만 어셈블리 코드를 오브젝트파일로 번역하기 할때, 몇몇 섹션의 값이 첨부 됩니다.

이러한 섹션들은 프로그램을 실행가능하게 링크되게하고 알맞게 프로그램을 실행 시킬때 필요한 섹션들이 되겠습니다.

 

마지막 작업이 오브젝트 파일을 링크시켜서 실행가능하도록 만드는 것이다. 이렇게하기위해서, 우리는 다음과 같은 명령어를 실행 해야 합니다.

# gcc -m32 hello.o -o hello
# ./hello
 

출력:

Hello World!
 

여기서 오브젝트 파일 hello.o를 실행가능하게 만들어 ./hello에 링크시키고 실행해 보았습니다.

그럼 다시 이 실행 ELF 파일을 들여다 본다면, 실행가능하도록 만들기 위해서 쓰여진 파일 섹션들 외에도 더 다른 많은 정보가 있다는 것을 볼 수가 있을 것입니다.

$ readelf -a hello
 
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2’s complement, little endian
Version: 1 (current)
OS/ABI: UNIX – System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048330
Start of program headers: 52 (bytes into file)
Start of section headers: 4392 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 10
Size of section headers: 40 (bytes)
Number of section headers: 30
Section header string table index: 27

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048174 000174 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048188 000188 000020 00 A 0 0 4
[ 3] .hash HASH 080481a8 0001a8 000028 04 A 5 0 4
[ 4] .gnu.hash GNU_HASH 080481d0 0001d0 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481f0 0001f0 000050 10 A 6 1 4
[ 6] .dynstr STRTAB 08048240 000240 00004c 00 A 0 0 1
[ 7] .gnu.version VERSYM 0804828c 00028c 00000a 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048298 000298 000020 00 A 6 1 4
[ 9] .rel.dyn REL 080482b8 0002b8 000008 08 A 5 0 4
[10] .rel.plt REL 080482c0 0002c0 000018 08 A 5 12 4
[11] .init PROGBITS 080482d8 0002d8 000017 00 AX 0 0 4
[12] .plt PROGBITS 080482f0 0002f0 000040 04 AX 0 0 16
[13] .text PROGBITS 08048330 000330 00019c 00 AX 0 0 16
[14] .fini PROGBITS 080484cc 0004cc 00001c 00 AX 0 0 4
[15] .rodata PROGBITS 080484e8 0004e8 000015 00 A 0 0 4
[16] .eh_frame_hdr PROGBITS 08048500 000500 000014 00 A 0 0 4
[17] .eh_frame PROGBITS 08048514 000514 000040 00 A 0 0 4
[18] .ctors PROGBITS 08049f0c 000f0c 000008 00 WA 0 0 4
[19] .dtors PROGBITS 08049f14 000f14 000008 00 WA 0 0 4
[20] .jcr PROGBITS 08049f1c 000f1c 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 08049f20 000f20 0000d0 08 WA 6 0 4
[22] .got PROGBITS 08049ff0 000ff0 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 08049ff4 000ff4 000018 04 WA 0 0 4
[24] .data PROGBITS 0804a00c 00100c 000008 00 WA 0 0 4
[25] .bss NOBITS 0804a014 001014 000008 00 WA 0 0 4
[26] .comment PROGBITS 00000000 001014 00002a 01 MS 0 0 1
[27] .shstrtab STRTAB 00000000 00103e 0000e9 00 0 0 1
[28] .symtab SYMTAB 00000000 0015d8 000340 10 29 32 4
[29] .strtab STRTAB 00000000 001918 00014d 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00140 0x00140 R E 0x4
INTERP 0x000174 0x08048174 0x08048174 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00554 0x00554 R E 0x1000
LOAD 0x000f0c 0x08049f0c 0x08049f0c 0x00108 0x00110 RW 0x1000
DYNAMIC 0x000f20 0x08049f20 0x08049f20 0x000d0 0x000d0 RW 0x4
NOTE 0x000188 0x08048188 0x08048188 0x00020 0x00020 R 0x4
GNU_EH_FRAME 0x000500 0x08048500 0x08048500 0x00014 0x00014 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
GNU_RELRO 0x000f0c 0x08049f0c 0x08049f0c 0x000f4 0x000f4 R 0x1
PAX_FLAGS 0x000000 0x00000000 0x00000000 0x00000 0x00000 0x4

Section to Segment mapping:
Segment Sections…
00
01 .interp
02 .interp .note.ABI-tag .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag
06 .eh_frame_hdr
07
08 .ctors .dtors .jcr .dynamic .got
09

Dynamic section at offset 0xf20 contains 21 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x80482d8
0x0000000d (FINI) 0x80484cc
0x00000004 (HASH) 0x80481a8
0x6ffffef5 (GNU_HASH) 0x80481d0
0x00000005 (STRTAB) 0x8048240
0x00000006 (SYMTAB) 0x80481f0
0x0000000a (STRSZ) 76 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x8049ff4
0x00000002 (PLTRELSZ) 24 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x80482c0
0x00000011 (REL) 0x80482b8
0x00000012 (RELSZ) 8 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x8048298
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x804828c
0x00000000 (NULL) 0x0

Relocation section ‘.rel.dyn’ at offset 0x2b8 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
08049ff0 00000206 R_386_GLOB_DAT 00000000 __gmon_start__

Relocation section ‘.rel.plt’ at offset 0x2c0 contains 3 entries:
Offset Info Type Sym.Value Sym. Name
0804a000 00000107 R_386_JUMP_SLOT 00000000 printf
0804a004 00000207 R_386_JUMP_SLOT 00000000 __gmon_start__
0804a008 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main

There are no unwind sections in this file.

Symbol table ‘.dynsym’ contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.0 (2)
2: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2)
4: 080484ec 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used

Symbol table ‘.symtab’ contains 52 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048174 0 SECTION LOCAL DEFAULT 1
2: 08048188 0 SECTION LOCAL DEFAULT 2
3: 080481a8 0 SECTION LOCAL DEFAULT 3
4: 080481d0 0 SECTION LOCAL DEFAULT 4
5: 080481f0 0 SECTION LOCAL DEFAULT 5
6: 08048240 0 SECTION LOCAL DEFAULT 6
7: 0804828c 0 SECTION LOCAL DEFAULT 7
8: 08048298 0 SECTION LOCAL DEFAULT 8
9: 080482b8 0 SECTION LOCAL DEFAULT 9
10: 080482c0 0 SECTION LOCAL DEFAULT 10
11: 080482d8 0 SECTION LOCAL DEFAULT 11
12: 080482f0 0 SECTION LOCAL DEFAULT 12
13: 08048330 0 SECTION LOCAL DEFAULT 13
14: 080484cc 0 SECTION LOCAL DEFAULT 14
15: 080484e8 0 SECTION LOCAL DEFAULT 15
16: 08048500 0 SECTION LOCAL DEFAULT 16
17: 08048514 0 SECTION LOCAL DEFAULT 17
18: 08049f0c 0 SECTION LOCAL DEFAULT 18
19: 08049f14 0 SECTION LOCAL DEFAULT 19
20: 08049f1c 0 SECTION LOCAL DEFAULT 20
21: 08049f20 0 SECTION LOCAL DEFAULT 21
22: 08049ff0 0 SECTION LOCAL DEFAULT 22
23: 08049ff4 0 SECTION LOCAL DEFAULT 23
24: 0804a00c 0 SECTION LOCAL DEFAULT 24
25: 0804a014 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 SECTION LOCAL DEFAULT 26
27: 00000000 0 FILE LOCAL DEFAULT ABS hello.c
28: 08049f0c 0 NOTYPE LOCAL DEFAULT 18 __init_array_end
29: 08049f20 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC
30: 08049f0c 0 NOTYPE LOCAL DEFAULT 18 __init_array_start
31: 08049ff4 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_
32: 08048490 5 FUNC GLOBAL DEFAULT 13 __libc_csu_fini
33: 08048495 0 FUNC GLOBAL HIDDEN 13 __i686.get_pc_thunk.bx
34: 0804a00c 0 NOTYPE WEAK DEFAULT 24 data_start
35: 00000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.0
36: 0804a014 0 NOTYPE GLOBAL DEFAULT ABS _edata
37: 080484cc 0 FUNC GLOBAL DEFAULT 14 _fini
38: 08049f18 0 OBJECT GLOBAL HIDDEN 19 __DTOR_END__
39: 0804a00c 0 NOTYPE GLOBAL DEFAULT 24 __data_start
40: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
41: 0804a010 0 OBJECT GLOBAL HIDDEN 24 __dso_handle
42: 080484ec 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used
43: 00000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
44: 08048430 90 FUNC GLOBAL DEFAULT 13 __libc_csu_init
45: 0804a01c 0 NOTYPE GLOBAL DEFAULT ABS _end
46: 08048330 0 FUNC GLOBAL DEFAULT 13 _start
47: 080484e8 4 OBJECT GLOBAL DEFAULT 15 _fp_hw
48: 0804a014 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
49: 08048404 29 FUNC GLOBAL DEFAULT 13 main
50: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
51: 080482d8 0 FUNC GLOBAL DEFAULT 11 _init

Histogram for bucket list length (total of 3 buckets):
Length Number % of total Coverage
0 0 ( 0.0%)
1 2 ( 66.7%) 50.0%
2 1 ( 33.3%) 100.0%

Histogram for `.gnu.hash’ bucket list length (total of 2 buckets):
Length Number % of total Coverage
0 1 ( 50.0%)
1 1 ( 50.0%) 100.0%

Version symbols section ‘.gnu.version’ contains 5 entries:
Addr: 000000000804828c Offset: 0x00028c Link: 5 (.dynsym)
000: 0 (*local*) 2 (GLIBC_2.0) 0 (*local*) 2 (GLIBC_2.0)
004: 1 (*global*)

Version needs section ‘.gnu.version_r’ contains 1 entries:
Addr: 0x0000000008048298 Offset: 0x000298 Link: 6 (.dynstr)
000000: Version: 1 File: libc.so.6 Cnt: 1
0x0010: Name: GLIBC_2.0 Flags: none Version: 2

Notes at offset 0x00000188 with length 0x00000020:
Owner Data size Description
GNU 0x00000010 NT_GNU_ABI_TAG (ABI version tag)
OS: Linux, ABI: 2.6.9
 

마치면서

우리는 지금 어떻게 C로 쓰여진 간단한 프로그램이 어셈블리 코드로 오브젝트 파일을 거쳐 최종적으로 실행가능한 파일로 변했는지 눈으로 보았습니다.

그냥 파일이 C 코드 뿐일때는 어떤 섹션도 가지지 않았으며, 프로그램의 어셈블리 언어내에 다음 두개의 섹션만 가지고 있었습니다: .rodata와 .text.

 

근데 이게 오브젝트 파일로 그리고 오브젝트에서 실행가능한 파일로 변했을 때,

파일은 프로그램이 성공적으로 수행하는 데 필요한 더욱 더 많은 섹션들을 가지게 되었다는 것이 중요 합니다.

 

​다음은 MinGW에서 실제적으로 실행 했을 때 출력 결과물이다.

약간 틀린면이 없지 않아 있습니다.( 그야 gcc 버전이 바꼈으니 당연한 결과 이겠지...)

부록 1. MinGW32에서 실제 만들어 본 hello.s

.file "hello.c"
.intel_syntax noprefix
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "Hello World!\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB6:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
and esp, -16
sub esp, 16
call ___main
mov DWORD PTR [esp], OFFSET FLAT:LC0
call _printf
mov eax, 0
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE6:
.ident "GCC: (GNU) 4.8.1"
.def _printf; .scl 2; .type 32; .endef
 

기존거 보다 많이 달라보이기는 하다. 아는 게 없으니 현상만 보자

 

부록2 MinGW32에서 오브젝트 파일과 실행 시 오류 메시지

$ file hello.o
 

출력:

hello.o: MS Windows COFF Intel 80386 object file
./hello.o: ./hello.o: cannot execute binary file
 

부록3. MinGW32에서 첫번째 readelf 실행

$ readelf -a hello.o
 

출력:

readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
 
 

https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html

 

GCC and Make - A Tutorial on how to compile, link and build C/C++ applications

GCC (GNU Compiler Collection) A Brief History and Introduction to GCC The original GNU C Compiler (GCC) is developed by Richard Stallman, the founder of the GNU Project. Richard Stallman founded the GNU project in 1984 to create a complete Unix-like operat

www3.ntu.edu.sg

 

안나온다 따라서 다음 명령어로 실행하면

$ nm hello.o
 
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .rdata
00000000 r .rdata$zzz
00000000 t .text
U ___main

00000000 T _main
U _printf
 

 

이상.


 

728x90