티스토리 뷰
안녕하세요 Hani입니다.
Mach-O가 빌드 프로세스나 Xcode 공부할 때 자꾸 튀어나와서 정리좀 해보려구해요.
Mach-O
Mach-O는 애플 OS에서 동작하는 컴파일된 프로그램에 대한 파일 포맷입니다.
오브젝트 파일(.o),
동적 라이브러리(.dylib),
정적 라이브러리(.a),
번들(.bundle)
커널 익스텐션(.kext)
Core Dump, Framework, Command-line Tool
요런 애들은 다 파일 포맷이 Mach-O인 거예요.
Mach-O는 크게 Header, Load Command, Segment Data 영역으로 나뉘어 있는데
하나씩 알아보러 갑시당. ✈️
Mach-O Header
애플 플랫폼에서 컴파일된 모든 것들은 다음과 같은 Mach-O 구조를 가지고 있어요.
(Header + Load Commands + Data)
그중 Mach-O의 헤더에는
해당 프로그램이 실행될 수 있는 CPU 아키텍쳐,
Executable가 어떤 타입인지,
헤더 다음에 오는 Load Command가 몇 개인지..
등에 대한 정보가 담겨 있습니다.
직접 Mach-O를 보기 위해 App이라는 프로젝트를 하나 만들어서 실행했습니다.
DerivedData 폴더에 프로젝트에 대한 Executable 파일이 생성됐고, 그걸 한 번 살펴볼게요.
애플은 Mach-O 파일을 읽을 수 있는 otool이라는 Command-line Tool을 제공하고 있어요.
otool만 입력하면 어떤 옵션이 있는지 알 수 있고
여기선 Mach Header를 보기 위해 -h를 입력했습니다.
그래도 모르겠음 ㅎ
Xcode - (Command + Shift + o) - /usr/include/mach-o/loader.h 를 입력하면
헤더의 각 정보가 뭘 의미하는지 볼 수 있습니다. ☺️
32비트를 위한 헤더와 64비트를 위한 헤더가 분리되어 있네욥.
올.. filetype 2랑 딱 맞음.
위에서 언급했던 파일들도 보이구
그럼 타입이 어디서 정해지느냐
Xcode - (Project or Target) - Build Settings - Linking - Mach-O Type에서 확인할 수 있습니다.
저기 mh_execute는 제가 집어넣은 게 아니고
Executable로 지정했다가 Other로 바꾸면
뭘로 지정할 거냐고 창이 뜨면서
기존에 지정한 타입(Executable)의 Default value(mh_execute)가 뜬 거예요..!
원하는 타입이 따로 있다면 Mach-O Type의 Other를 누르고
위에 있는 filetype에 맞게 입력해주면 됩니다.
filetype 등의 정보를 loader.h에서 확인할 수 있지만
다른 정보(ex. cpu)는 loader.h에 include된 <mach/machine.h> 등에서 찾을 수 있습니다.
이럴 땐 /mach/machine.h 를 탐색하면 됨..!
이제 Mach-O의 헤더에 대해서 좀 알 것 같죠? ☺️
근데 끝이 아님..
두 개 이상의 Mach-O로 이루어진 그룹이 생길 수도 있습니다.
이때, Fat Header가 그룹 내 모든 Mach-O Header의 magic이라는 필드에 대한 정보를 가지고 있는데
magic은 각 Mach-O 파일에 대한 identifier기 때문에
Fat Header에서 각 Mach-O를 구별할 수 있습니다.
/usr/include/mach-o/fat.h에서 Fat Header에 대하여 확인할 수 있습니다.
이렇게 여러 개의 Executable이 합쳐져 있는 경우는
비트 수가 다른 아키텍쳐를 둘 다 컴파일하여 하나의 파일로 합치는 상황이 대표적인 예시예요.
그래서 Fat Architecture도 비트 수에 따라 나뉘어 있습니다.
Mach-O Load Command
Load Command는 Executable이 어떻게 메모리에 로드되어야 하는지에 대한 정보를 가지고 있어요.
Load Command는 크기와 Argument가 다른 구조체 배열로 이루어져 있습니다.
otool의 -l 옵션을 통해 Mach-O의 Load Command들을 볼 수 있습니다.
Load Command가 총 35개라서 하나만 잘라왔어요.
(-h 옵션을 통해 헤더를 찾아봤을 때 Load Command의 개수랑 일치하는지 확인해보면 좋을듯..!)
가상 메모리, 후술 할 Segment의 개수 등에 대한 정보를 가지고 있네요.
Load Command를 이루는 구조체들은 서로의 Argument가 동일하지 않지만
첫 두 변수가 cmd, cmdsize 변수로 고정되어 있습니다.
cmd는 Load Command의 타입이며, cmdsize는 struct의 크기를 의미하는데
위에서 cmd를 보면 LC_SEGMENT_64로 되어있네요.
mach-o/loader.h 파일을 다시 보면 이렇게 정의되어있는 걸 확인할 수 있습니다.
mach-o/loader.h 파일에서
LC_SEGMENT_64에 대응되는 구조체인 segment_command_64를 찾을 수 있습니다.
Load Command에 대하여 조금 분석이 된 느낌이네요. 🥰
하나만 더 짚고 넘어갈게요..!
0번째 Load Command의 Segment 이름이 __PAGEZERO라는 것과
Segment의 개수(nsects)가 0인 것을 기억해두세요.
Mach-O Segment
Segment는 Permission에 대한 정보를 갖고 있습니다.
Segment는 Section 서브 컴포넌트를 0개에서 255개까지 가지고 있습니다.
Load Command가 Segment 정보와 0개 이상의 Section 개수(nsects)를 가지고 있다면
Mach-O의 Data 영역에서 나타나게 됩니다.
몇 가지 Segment만 알아볼게요. ☺️
__PAGEZERO Segment
Static Linker는 PAGEZERO Segment를 Executable의 첫 번째 Segment로 생성합니다.
이 Segment는 가상 메모리 상에서 0에 위치하게 되며
이 메모리 영역은 r, w, x에 대한 Permission이 없습니다.
또한 PAGEZERO는 0개의 Section을 가지고 있습니다.
아까 0번째 Load Command는 segname을 __PAGEZERO, nsects를 0을 가지고 있었죠?
그래서 Data 영역에 아무것도 없던 거예요.
__TEXE Segment
Executable 코드와 읽기 전용 데이터를 가지고 있기 때문에 r, x에 대한 권한을 가지고 있습니다.
따라서 immutable한 데이터를 저장하기 위해 다수의 Section을 가지고 있어요.
__DATA_CONST
🥺
__DATA Segment
쓰기 가능한 데이터를 가지고 있어서 r, w, x에 대한 권한을 모두 가지고 있습니다.
따라서 mutable한 데이터를 저장하기 위해 다수의 Section을 가지고 있습니다.
__LINKEDIT Segment
Dynamic Linker에 의해 사용되는 Symbol, Entitlement 등의 Raw Data를 가지고 있습니다.
r 권한만 가지고 있고, 많은 정보가 담겨있는 Segment지만 Section가 없습니다.
...
다른 Load Command, Segment, Section도 다뤄보고 싶지만
너무 많은 내용을 담을 것 같아서
다음 포스팅에서 쓰겠습니다. ☺️
에.. Mach-O에 대하여 살펴봤는데욥.
찾아보니 코드 서명, 보안, 디버깅, 리버스 엔지니어링 등..
많은 것과 연관이 있다는 것을 알았어요.
생각보다 거대한 걸 건드렸을지도..
References
https://www.apriorit.com/dev-blog/363-how-to-reverse-engineer-os-x-and-ios-software
https://en.wikipedia.org/wiki/Mach-O
https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW105
https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOTopics/0-Introduction/introduction.html#//apple_ref/doc/uid/TP40001519
https://www.unix.com/man-page/osx/1/otool/
https://github.com/aidansteele/osx-abi-macho-file-format-reference
https://developer.apple.com/library/archive/documentation/Performance/Conceptual/CodeFootprint/CodeFootprint.html#//apple_ref/doc/uid/10000149-SW1
'Apple' 카테고리의 다른 글
[Apple] M1 맥북 Cocoa Pods / Rosetta Terminal (0) | 2021.02.21 |
---|
- Total
- Today
- Yesterday
- 강한 순환 참조
- Testable
- 최단경로문제
- 최대 매칭
- 포드 풀커슨 알고리즘
- CompositionalLayout
- MeTal
- 네트워크 유량
- 다익스트라 시간복잡도
- 부스트캠프 6기
- 최단경로 알고리즘
- mach-o
- CPU와 Memory
- WWDC16
- WWDC21
- 네트워크 플로우
- 코딩대회
- test coverage
- observeOn
- 벨만포드 시간복잡도
- WWDC17
- State Restoration
- 벨만포드 알고리즘
- 에드몬드 카프 알고리즘
- 컴퓨터 추상화
- rxswift
- WWDC19
- 최단경로 문제
- HIG
- IOS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |