llvm.org GIT mirror llvm / 4877ca7
[obj2yaml] [yaml2obj] MachO support for rebase opcodes This is the first bit of support for MachO __LINKEDIT segment data. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@270724 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Bieneman 3 years ago
5 changed file(s) with 266 addition(s) and 23 deletion(s). Raw diff Collapse all Expand all
5656 uint64_t ZeroPadBytes;
5757 };
5858
59 struct RebaseOpcode {
60 MachO::RebaseOpcode Opcode;
61 uint8_t Imm;
62 std::vector ExtraData;
63 };
64
65 struct LinkEditData {
66 std::vector RebaseOpcodes;
67 };
68
5969 struct Object {
6070 FileHeader Header;
6171 std::vector LoadCommands;
6272 std::vector
Sections;
73 LinkEditData LinkEdit;
6374 };
6475
6576 } // namespace llvm::MachOYAML
6879 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::LoadCommand)
6980 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::Section)
7081 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex8)
82 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::Hex64)
83 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MachOYAML::RebaseOpcode)
7184
7285 namespace llvm {
7386 namespace yaml {
8497 static void mapping(IO &IO, MachOYAML::LoadCommand &LoadCommand);
8598 };
8699
100 template <> struct MappingTraits {
101 static void mapping(IO &IO, MachOYAML::LinkEditData &LinkEditData);
102 };
103
104 template <> struct MappingTraits {
105 static void mapping(IO &IO, MachOYAML::RebaseOpcode &RebaseOpcode);
106 };
107
87108 template <> struct MappingTraits {
88109 static void mapping(IO &IO, MachOYAML::Section &Section);
89110 };
95116 static void enumeration(IO &io, MachO::LoadCommandType &value) {
96117 #include "llvm/Support/MachO.def"
97118 io.enumFallback(value);
119 }
120 };
121
122 #define ENUM_CASE(Enum) \
123 io.enumCase(value, #Enum, MachO::Enum);
124
125 template <> struct ScalarEnumerationTraits {
126 static void enumeration(IO &io, MachO::RebaseOpcode &value) {
127 ENUM_CASE(REBASE_OPCODE_DONE)
128 ENUM_CASE(REBASE_OPCODE_SET_TYPE_IMM)
129 ENUM_CASE(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB)
130 ENUM_CASE(REBASE_OPCODE_ADD_ADDR_ULEB)
131 ENUM_CASE(REBASE_OPCODE_ADD_ADDR_IMM_SCALED)
132 ENUM_CASE(REBASE_OPCODE_DO_REBASE_IMM_TIMES)
133 ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES)
134 ENUM_CASE(REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB)
135 ENUM_CASE(REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB)
136 io.enumFallback(value);
98137 }
99138 };
100139
9292 }
9393 IO.mapRequired("FileHeader", Object.Header);
9494 IO.mapOptional("LoadCommands", Object.LoadCommands);
95 IO.mapOptional("LinkEditData", Object.LinkEdit);
9596 IO.setContext(nullptr);
97 }
98
99 void MappingTraits::mapping(IO &IO,
100 MachOYAML::LinkEditData &LinkEditData) {
101 IO.mapOptional("RebaseOpcodes", LinkEditData.RebaseOpcodes);
102 }
103
104 void MappingTraits::mapping(IO &IO,
105 MachOYAML::RebaseOpcode &RebaseOpcode) {
106 IO.mapRequired("Opcode", RebaseOpcode.Opcode);
107 IO.mapRequired("Imm", RebaseOpcode.Imm);
108 IO.mapOptional("ExtraData", RebaseOpcode.ExtraData);
96109 }
97110
98111 template
0 # RUN: yaml2obj -format=macho %s | obj2yaml | FileCheck %s
1
2 --- !mach-o
3 FileHeader:
4 magic: 0xFEEDFACF
5 cputype: 0x01000007
6 cpusubtype: 0x80000003
7 filetype: 0x00000002
8 ncmds: 4
9 sizeofcmds: 224
10 flags: 0x00218085
11 reserved: 0x00000000
12 LoadCommands:
13 - cmd: LC_SEGMENT_64
14 cmdsize: 72
15 segname: __LINKEDIT
16 vmaddr: 4294979584
17 vmsize: 4096
18 fileoff: 1024
19 filesize: 2508
20 maxprot: 7
21 initprot: 1
22 nsects: 0
23 flags: 0
24 - cmd: LC_DYLD_INFO_ONLY
25 cmdsize: 48
26 rebase_off: 1024
27 rebase_size: 8
28 bind_off: 1032
29 bind_size: 96
30 weak_bind_off: 0
31 weak_bind_size: 0
32 lazy_bind_off: 1128
33 lazy_bind_size: 624
34 export_off: 1752
35 export_size: 48
36 - cmd: LC_SYMTAB
37 cmdsize: 24
38 symoff: 1816
39 nsyms: 30
40 stroff: 2436
41 strsize: 1096
42 - cmd: LC_DYSYMTAB
43 cmdsize: 80
44 ilocalsym: 0
45 nlocalsym: 9
46 iextdefsym: 9
47 nextdefsym: 2
48 iundefsym: 11
49 nundefsym: 19
50 tocoff: 0
51 ntoc: 0
52 modtaboff: 0
53 nmodtab: 0
54 extrefsymoff: 0
55 nextrefsyms: 0
56 indirectsymoff: 2296
57 nindirectsyms: 35
58 extreloff: 0
59 nextrel: 0
60 locreloff: 0
61 nlocrel: 0
62 LinkEditData:
63 RebaseOpcodes:
64 - Opcode: REBASE_OPCODE_SET_TYPE_IMM
65 Imm: 1
66 - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
67 Imm: 2
68 ExtraData:
69 - 0x0000000000000028
70 - Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES
71 Imm: 0
72 ExtraData:
73 - 0x000000000000000F
74 - Opcode: REBASE_OPCODE_DONE
75 Imm: 0
76 ...
77
78 #CHECK: LinkEditData:
79 #CHECK: RebaseOpcodes:
80 #CHECK: - Opcode: REBASE_OPCODE_SET_TYPE_IMM
81 #CHECK: Imm: 1
82 #CHECK: - Opcode: REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
83 #CHECK: Imm: 2
84 #CHECK: ExtraData:
85 #CHECK: - 0x0000000000000028
86 #CHECK: - Opcode: REBASE_OPCODE_DO_REBASE_ULEB_TIMES
87 #CHECK: Imm: 0
88 #CHECK: ExtraData:
89 #CHECK: - 0x000000000000000F
90 #CHECK: - Opcode: REBASE_OPCODE_DONE
91 #CHECK: Imm: 0
1111 #include "llvm/Object/MachOUniversal.h"
1212 #include "llvm/ObjectYAML/MachOYAML.h"
1313 #include "llvm/Support/ErrorHandling.h"
14 #include "llvm/Support/LEB128.h"
1415
1516 #include // for memcpy
1617
2425 const llvm::object::MachOObjectFile::LoadCommandInfo &LoadCmd);
2526
2627 const object::MachOObjectFile &Obj;
28 void dumpHeader(std::unique_ptr &Y);
29 void dumpLoadCommands(std::unique_ptr &Y);
30 void dumpLinkEdit(std::unique_ptr &Y);
2731
2832 public:
2933 MachODumper(const object::MachOObjectFile &O) : Obj(O) {}
143147
144148 Expected> MachODumper::dump() {
145149 auto Y = make_unique();
150 dumpHeader(Y);
151 dumpLoadCommands(Y);
152 dumpLinkEdit(Y);
153 return std::move(Y);
154 }
155
156 void MachODumper::dumpHeader(std::unique_ptr &Y) {
146157 Y->Header.magic = Obj.getHeader().magic;
147158 Y->Header.cputype = Obj.getHeader().cputype;
148159 Y->Header.cpusubtype = Obj.getHeader().cpusubtype;
151162 Y->Header.sizeofcmds = Obj.getHeader().sizeofcmds;
152163 Y->Header.flags = Obj.getHeader().flags;
153164 Y->Header.reserved = 0;
154
165 }
166
167 void MachODumper::dumpLoadCommands(std::unique_ptr &Y) {
155168 for (auto LoadCmd : Obj.load_commands()) {
156169 MachOYAML::LoadCommand LC;
157170 const char *EndPtr = LoadCmd.Ptr;
175188 LC.ZeroPadBytes = RemainingBytes;
176189 Y->LoadCommands.push_back(std::move(LC));
177190 }
178
179 return std::move(Y);
191 }
192
193 void MachODumper::dumpLinkEdit(std::unique_ptr &Y) {
194 MachOYAML::LinkEditData &LEData = Y->LinkEdit;
195
196 auto RebaseOpcodes = Obj.getDyldInfoRebaseOpcodes();
197 for (auto OpCode = RebaseOpcodes.begin(); OpCode != RebaseOpcodes.end();
198 ++OpCode) {
199 MachOYAML::RebaseOpcode RebaseOp;
200 RebaseOp.Opcode =
201 static_cast(*OpCode & MachO::REBASE_OPCODE_MASK);
202 RebaseOp.Imm = *OpCode & MachO::REBASE_IMMEDIATE_MASK;
203
204 unsigned Count;
205 uint64_t ULEB = 0;
206
207 switch (RebaseOp.Opcode) {
208 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
209
210 ULEB = decodeULEB128(OpCode + 1, &Count);
211 RebaseOp.ExtraData.push_back(ULEB);
212 OpCode += Count;
213 // Intentionally no break here -- This opcode has two ULEB values
214 case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
215 case MachO::REBASE_OPCODE_ADD_ADDR_ULEB:
216 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
217 case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
218
219 ULEB = decodeULEB128(OpCode + 1, &Count);
220 RebaseOp.ExtraData.push_back(ULEB);
221 OpCode += Count;
222 break;
223 default:
224 break;
225 }
226
227 LEData.RebaseOpcodes.push_back(RebaseOp);
228
229 if (RebaseOp.Opcode == MachO::REBASE_OPCODE_DONE)
230 break;
231 }
180232 }
181233
182234 Error macho2yaml(raw_ostream &Out, const object::MachOObjectFile &Obj) {
1414 #include "yaml2obj.h"
1515 #include "llvm/ObjectYAML/MachOYAML.h"
1616 #include "llvm/Support/Error.h"
17 #include "llvm/Support/LEB128.h"
1718 #include "llvm/Support/MachO.h"
1819 #include "llvm/Support/YAMLTraits.h"
1920 #include "llvm/Support/raw_ostream.h"
21
22 #include "llvm/Support/Format.h"
2023
2124 using namespace llvm;
2225
4144 Error writeHeader(raw_ostream &OS);
4245 Error writeLoadCommands(raw_ostream &OS);
4346 Error writeSectionData(raw_ostream &OS);
47 Error writeLinkEditData(raw_ostream &OS);
48
49 void ZeroToOffset(raw_ostream &OS, size_t offset);
4450
4551 MachOYAML::Object &Obj;
4652 bool is64Bit;
164170 OS.write(reinterpret_cast(FillData.data()), Size);
165171 }
166172
173 void MachOWriter::ZeroToOffset(raw_ostream &OS, size_t Offset) {
174 auto currOffset = OS.tell() - fileStart;
175 if (currOffset < Offset)
176 ZeroFillBytes(OS, Offset - currOffset);
177 }
178
167179 Error MachOWriter::writeLoadCommands(raw_ostream &OS) {
168180 for (auto &LC : Obj.LoadCommands) {
169181 size_t BytesWritten = 0;
211223 switch (LC.Data.load_command_data.cmd) {
212224 case MachO::LC_SEGMENT:
213225 case MachO::LC_SEGMENT_64:
226 auto currOffset = OS.tell() - fileStart;
227 auto segname = LC.Data.segment_command_data.segname;
214228 uint64_t segOff = is64Bit ? LC.Data.segment_command_64_data.fileoff
215229 : LC.Data.segment_command_data.fileoff;
216230
217 // Zero Fill any data between the end of the last thing we wrote and the
218 // start of this section.
219 auto currOffset = OS.tell() - fileStart;
220 if (currOffset < segOff) {
221 ZeroFillBytes(OS, segOff - currOffset);
222 }
223
224 for (auto &Sec : LC.Sections) {
231 if (0 == strncmp(&segname[0], "__LINKEDIT", 16)) {
232 if (auto Err = writeLinkEditData(OS))
233 return Err;
234 } else {
225235 // Zero Fill any data between the end of the last thing we wrote and the
226236 // start of this section.
227 assert(OS.tell() - fileStart <= Sec.offset &&
228 "Wrote too much data somewhere, section offsets don't line up.");
229 currOffset = OS.tell() - fileStart;
230 if (currOffset < Sec.offset) {
231 ZeroFillBytes(OS, Sec.offset - currOffset);
237 if (currOffset < segOff) {
238 ZeroFillBytes(OS, segOff - currOffset);
232239 }
233240
234 // Fills section data with 0xDEADBEEF
235 Fill(OS, Sec.size, 0xDEADBEEFu);
241 for (auto &Sec : LC.Sections) {
242 // Zero Fill any data between the end of the last thing we wrote and
243 // the
244 // start of this section.
245 assert(
246 OS.tell() - fileStart <= Sec.offset &&
247 "Wrote too much data somewhere, section offsets don't line up.");
248 currOffset = OS.tell() - fileStart;
249 if (currOffset < Sec.offset) {
250 ZeroFillBytes(OS, Sec.offset - currOffset);
251 }
252
253 // Fills section data with 0xDEADBEEF
254 Fill(OS, Sec.size, 0xDEADBEEFu);
255 }
236256 }
237257 uint64_t segSize = is64Bit ? LC.Data.segment_command_64_data.filesize
238258 : LC.Data.segment_command_data.filesize;
239 currOffset = OS.tell() - fileStart;
240 if (currOffset < segOff + segSize) {
241 // Fills segment data not covered by a section with 0xBAADDA7A
242 Fill(OS, (segOff + segSize) - currOffset, 0xBAADDA7Au);
243 }
259 ZeroToOffset(OS, segOff + segSize);
244260 break;
245261 }
246262 }
263 return Error::success();
264 }
265
266 Error MachOWriter::writeLinkEditData(raw_ostream &OS) {
267 MachOYAML::LinkEditData &LinkEdit = Obj.LinkEdit;
268 MachO::dyld_info_command *DyldInfoOnlyCmd = 0;
269 MachO::symtab_command *SymtabCmd = 0;
270 for (auto &LC : Obj.LoadCommands) {
271 switch (LC.Data.load_command_data.cmd) {
272 case MachO::LC_SYMTAB:
273 SymtabCmd = &LC.Data.symtab_command_data;
274 break;
275 case MachO::LC_DYLD_INFO_ONLY:
276 DyldInfoOnlyCmd = &LC.Data.dyld_info_command_data;
277 break;
278 }
279 }
280
281 ZeroToOffset(OS, DyldInfoOnlyCmd->rebase_off);
282
283 for (auto Opcode : LinkEdit.RebaseOpcodes) {
284 uint8_t OpByte = Opcode.Opcode | Opcode.Imm;
285 OS.write(reinterpret_cast(&OpByte), 1);
286 for (auto Data : Opcode.ExtraData) {
287 encodeULEB128(Data, OS);
288 }
289 }
290
291 // Fill to the end of the string table
292 ZeroToOffset(OS, SymtabCmd->stroff + SymtabCmd->strsize);
293
247294 return Error::success();
248295 }
249296