컴파일이야 고급 언어를 (특정 하드웨어 플랫폼에 맞는) 기계어로 번역하는 과정으로

이 기계어를 인스트럭션이라고 하며, 이 인스트럭션을 어셈블리어로 나타낼수있음.

 

01010101 의 경우 i386 CPU에서 ebp 레지스터의 값을 스택에 push하는 명령

 

 

1. objdump, xxd로 한번 보기

예제로 이 코드를 작성해서 어셈블리어로 보면

objdump : 바이너리 파일을 보는 명령

-S 옵션 : 디버깅 심벌과 인스트럭션, 어셈블리 코드 보여줌

위 덤프 내용은

C 소스코드 부분인 디버깅 심볼과

주소, 명령, 어셈블리 로 구성되있고,

초기화 종료 코드가 들어가 main 이외에도 아주 길다.

 

 

아쉽게도 이 플랫폼은 x86-64라 i386계열과 다른 명령어 셋인지 인스트럭션이 좀 다르게 나온다 ;

 

파일을 16진수로 보여주는 xxd로 열면 이런식으로 나온다.

 

 

 

2. 컴파일 과정

2.1 gcc x86_64-linux

gcc : ARM, DEC< AVR, i386등 아주 많은 아키텍처 지원하며, C뿐만 아닌 C++, fortran, objective-c도 컴파일 가능

이 경로의 실행파일로 cc1, cc1plus, collect2, f951이 있는데

cc1 : c컴파일러

cc1plus : c++ 컴파일러

f951 : 포트란 컴파일러

collect2 : 링커

* lto 는 찾아보니 링크 속도 최적화기? 라고 나온다.

* 원랜 전처리기 cpp0도 있다고 하는데 왜 여기는 없는진 모르겠다.

 

한번 컴파일해서 내용좀 보면

gcc -v --save-temps -o like like.c에서

-v는 컴파일 과정을 화면 출력 verbose?

--save-temps는 중간 파일 남겨두는 명령(전처리 파일 .i와 어셈블리파일 .s를 지우지 않고 나둔다)

 

위 내용을 보면 패키지 버전이 우분투 9.4.0-우분투1 20.0 4 1이고, 프로그램 프리픽스는 x86-64-linux-gnu

맨 마지막 줄쯤 보면 build, 호스트, 타겟이 x86_64-linux-gnu로 다 같다.

대강 우분투 20.04에서 돌아가는 gcc 9.4.0가지고 저런 설정으로 빌드한다는 소린거같다.

 

찾아보면 cc1과 collect2는 보이는데 전처리기와 어셈블러는 어디서 썻는질 모르겠다.

 

나온걸 보면 전처리 파일 like.i와 어셈블리 파일 like.s, 목적 파일 like.o가 보인다.

 

 

좌측은 전처리 결과, 우측은 어셈블리 코드

 

 

2.2 중간 파일의 유용함

이렇게 코드를 작성한 상태에서

 

gcc를 돌리면 like.c에 MY가 없다고 에러가 뜬다.

my_struct를 my란 이름으로 줬지만 like.c 에선 MY로 되어버려 선언되지 않은거라 에러가 뜬다.

 

하지만 보통 여러 헤드파일을 include 하고, 그 인클루드한 헤더가 다른걸 인클루드한 상태에서

심볼 정의 안했다는 에러가 뜨는 경우 찾기 힘들지만 전처리 파일인 like.i를 보면 그나마 쉽게 찾을수 있다?고 한다.

이게 뭔소린진 제대로 만나보질 않아서 아직은 잘 모르겠다.

 

 

보다가 왜 전처리 cpp0가 없나 했는데

cc1 옵션으로 -fpreprocessed like.i가 있는걸 봐선

cc1가 전처리하는 내용도 포함하고 있나보다.

 

전처리 과정을 제대로 보고싶긴한데 워낙 오래된 자료라 이 환경에서 맞출수 없어 pass

컴파일해서 어셈블리 까지 가는건 그냥 넘어가고

 

3. 바이너리

 

like.c 코드를 이걸로 돌아와 다시 진행하면

 

as 명령어로 like.s에서 ELF 바이너리 like.o를 만들었다.

링커는 여러 오브젝트 파일을 링크할때 인스트럭션과 데이터의 범위 등 바이너리의 구조를 알아야 잘 링크시킬수 있고

유닉스 바이너리 포멧으로 a.out, ELF 등이 있음.

 

3.1 바이너리 포멧

표준 ELF 포멧에 대해선 그림이 조금씩 다른게 여러개가 있는데

위키에서는 ELF

1. 실행, 목적, 공유라이브러리, 코어 덤프를 위한 표준 형식

2. 0개 이상의 세그먼트를 정의하는 프로그램 해더 테이블, 0개 이상 섹션을 정의한 섹션해더 테이블, 참조 데이터

3. 섹션은 링킹과 재배치에 필요한 정보 포함, 세그먼트는 런타임에 필요한 정보 가짐

4. 두 관점보면 ELF 파일의 프로그램 해더는 런타임시 세그먼트를 나타내고, 섹션해더는 바이너리 섹션의 집합

 

이게 아직 뭔소린가 싶다.

 

 

on1ystar 님의 블로그를 보면

ELF 헤더 : 파일 구성 

섹션 : 링킹에 필요한 obj 파일 정보(인스트럭션, 데이터, 심볼테이블, 재배치 등)

프로그램 헤더 테이블 : 프로세스 이미지 만드는 방식?

섹션 헤더 테이블 : 파일 섹션에 대한 정보

https://bnzn2426.tistory.com/82

 

ELF 파일 구조

ELF (Executable and Linkable Format) 유닉스 계열 시스템들의 표준 바이너리 파일로 실행 파일, 목적 파일. 공유 라이브러리 그리고 코어 덤프를 위한 표준 파일 형식 보통 ELF 파일은 ELF Header + program hea..

bnzn2426.tistory.com

 

일단 ELF 표준 포멧은 대충 넘어가고

read -a 바이너리파일 로  ELF 포멧 정보를 볼 수 있다.

 

 

지금 like.o 파일의 구조는

이런식이라고 한다.

 

 

ELF 헤더

인스트럭션 : like.s를 어셈블하여 만듬

데이터 : 전역변수가 없어서 쓰진 않으나, 있으면 전역변수 공간을 할당받음

GCC 컴파일러 버전정보

기타 섹션 : 심볼 테이블 + 재배치 섹션

* 심볼 테이블 : like.c의 심볼 정보들을 가짐 (심볼 : 메모리 주소를 가진 모든것 ex.전역변수, 구조체, 함수, 크기, 종류 등)

 

지금 작성한 코드에는 main 함수랑 printf 를쓰긴 했는데 printf가 결국 puts나 똑같아서 그런가? printf는 보이진 않는다.

 

옛날이랑 좀 달라졋는지 재배치 섹션은 심볼테이블보다 먼저 나오는데,

시간이 없어 일단 여기서 끝

+ Recent posts