authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-09-09 09:00:24+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-09-09 09:00:24+02:00
log7d487a41627658bfda37f1f06f8e453c2b576b9c
treee914dd539abbf953de3e15104492b52734688189
parentedc40157eb3b547f86185e2f85c08daf928eb9f1
parentedbfd04ec1fa11fde88166c4b906b7868cbbf218
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6289 from kubkon/macho

macho: fix bug where __text section would get overwritten

2 files changed, 134 insertions(+), 23 deletions(-)

lib/std/macho.zig+110-7
......@@ -647,6 +647,32 @@ pub const nlist_64 = extern struct {
647647 n_value: u64,
648648};
649649
650/// Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD
651/// format. The modifications from the original format were changing the value
652/// of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
653/// This modification is required to support symbols in an arbitrary number of
654/// sections not just the three sections (text, data and bss) in a 4.3BSD file.
655/// Also the last 4 bits have had the r_type tag added to them.
656pub const relocation_info = packed struct {
657 /// offset in the section to what is being relocated
658 r_address: i32,
659
660 /// symbol index if r_extern == 1 or section ordinal if r_extern == 0
661 r_symbolnum: u24,
662
663 /// was relocated pc relative already
664 r_pcrel: u1,
665
666 /// 0=byte, 1=word, 2=long, 3=quad
667 r_length: u2,
668
669 /// does not include value of sym referenced
670 r_extern: u1,
671
672 /// if not 0, machine specific relocation type
673 r_type: u4,
674};
675
650676/// After MacOS X 10.1 when a new load command is added that is required to be
651677/// understood by the dynamic linker for the image to execute properly the
652678/// LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic
......@@ -1086,13 +1112,58 @@ pub const N_ECOML = 0xe8;
10861112/// second stab entry with length information
10871113pub const N_LENG = 0xfe;
10881114
1089/// If a segment contains any sections marked with S_ATTR_DEBUG then all
1090/// sections in that segment must have this attribute. No section other than
1091/// a section marked with this attribute may reference the contents of this
1092/// section. A section with this attribute may contain no symbols and must have
1093/// a section type S_REGULAR. The static linker will not copy section contents
1094/// from sections with this attribute into its output file. These sections
1095/// generally contain DWARF debugging info.
1115// For the two types of symbol pointers sections and the symbol stubs section
1116// they have indirect symbol table entries. For each of the entries in the
1117// section the indirect symbol table entries, in corresponding order in the
1118// indirect symbol table, start at the index stored in the reserved1 field
1119// of the section structure. Since the indirect symbol table entries
1120// correspond to the entries in the section the number of indirect symbol table
1121// entries is inferred from the size of the section divided by the size of the
1122// entries in the section. For symbol pointers sections the size of the entries
1123// in the section is 4 bytes and for symbol stubs sections the byte size of the
1124// stubs is stored in the reserved2 field of the section structure.
1125
1126/// section with only non-lazy symbol pointers
1127pub const S_NON_LAZY_SYMBOL_POINTERS = 0x6;
1128
1129/// section with only lazy symbol pointers
1130pub const S_LAZY_SYMBOL_POINTERS = 0x7;
1131
1132/// section with only symbol stubs, byte size of stub in the reserved2 field
1133pub const S_SYMBOL_STUBS = 0x8;
1134
1135/// section with only function pointers for initialization
1136pub const S_MOD_INIT_FUNC_POINTERS = 0x9;
1137
1138/// section with only function pointers for termination
1139pub const S_MOD_TERM_FUNC_POINTERS = 0xa;
1140
1141/// section contains symbols that are to be coalesced
1142pub const S_COALESCED = 0xb;
1143
1144/// zero fill on demand section (that can be larger than 4 gigabytes)
1145pub const S_GB_ZEROFILL = 0xc;
1146
1147/// section with only pairs of function pointers for interposing
1148pub const S_INTERPOSING = 0xd;
1149
1150/// section with only 16 byte literals
1151pub const S_16BYTE_LITERALS = 0xe;
1152
1153/// section contains DTrace Object Format
1154pub const S_DTRACE_DOF = 0xf;
1155
1156/// section with only lazy symbol pointers to lazy loaded dylibs
1157pub const S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10;
1158
1159// If a segment contains any sections marked with S_ATTR_DEBUG then all
1160// sections in that segment must have this attribute. No section other than
1161// a section marked with this attribute may reference the contents of this
1162// section. A section with this attribute may contain no symbols and must have
1163// a section type S_REGULAR. The static linker will not copy section contents
1164// from sections with this attribute into its output file. These sections
1165// generally contain DWARF debugging info.
1166
10961167/// a debug section
10971168pub const S_ATTR_DEBUG = 0x02000000;
10981169
......@@ -1154,3 +1225,35 @@ pub const VM_PROT_WRITE: vm_prot_t = 0x2;
11541225
11551226/// VM execute permission
11561227pub const VM_PROT_EXECUTE: vm_prot_t = 0x4;
1228
1229pub const reloc_type_x86_64 = packed enum(u4) {
1230 /// for absolute addresses
1231 X86_64_RELOC_UNSIGNED = 0,
1232
1233 /// for signed 32-bit displacement
1234 X86_64_RELOC_SIGNED,
1235
1236 /// a CALL/JMP instruction with 32-bit displacement
1237 X86_64_RELOC_BRANCH,
1238
1239 /// a MOVQ load of a GOT entry
1240 X86_64_RELOC_GOT_LOAD,
1241
1242 /// other GOT references
1243 X86_64_RELOC_GOT,
1244
1245 /// must be followed by a X86_64_RELOC_UNSIGNED
1246 X86_64_RELOC_SUBTRACTOR,
1247
1248 /// for signed 32-bit displacement with a -1 addend
1249 X86_64_RELOC_SIGNED_1,
1250
1251 /// for signed 32-bit displacement with a -2 addend
1252 X86_64_RELOC_SIGNED_2,
1253
1254 /// for signed 32-bit displacement with a -4 addend
1255 X86_64_RELOC_SIGNED_4,
1256
1257 /// for thread local variables
1258 X86_64_RELOC_TLV,
1259};
src-self-hosted/link/MachO.zig+24-16
......@@ -32,6 +32,20 @@ const LoadCommand = union(enum) {
3232 .Dysymtab => |x| x.cmdsize,
3333 };
3434 }
35
36 pub fn write(self: LoadCommand, file: *fs.File, offset: u64) !void {
37 return switch (self) {
38 .Segment => |cmd| writeGeneric(cmd, file, offset),
39 .LinkeditData => |cmd| writeGeneric(cmd, file, offset),
40 .Symtab => |cmd| writeGeneric(cmd, file, offset),
41 .Dysymtab => |cmd| writeGeneric(cmd, file, offset),
42 };
43 }
44
45 fn writeGeneric(cmd: anytype, file: *fs.File, offset: u64) !void {
46 const slice = [1]@TypeOf(cmd){cmd};
47 return file.pwriteAll(mem.sliceAsBytes(slice[0..1]), offset);
48 }
3549};
3650
3751base: File,
......@@ -258,8 +272,7 @@ pub fn flush(self: *MachO, module: *Module) !void {
258272
259273 var last_cmd_offset: usize = @sizeOf(macho.mach_header_64);
260274 for (self.load_commands.items) |cmd| {
261 const cmd_to_write = [1]@TypeOf(cmd){cmd};
262 try self.base.file.?.pwriteAll(mem.sliceAsBytes(cmd_to_write[0..1]), last_cmd_offset);
275 try cmd.write(&self.base.file.?, last_cmd_offset);
263276 last_cmd_offset += cmd.cmdsize();
264277 }
265278 const off = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);
......@@ -346,19 +359,18 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
346359 .n_desc = 0,
347360 .n_value = addr,
348361 };
349 self.offset_table.items[decl.link.macho.offset_table_index.?] = addr;
350362
363 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
364 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
365 try self.updateDeclExports(module, decl, decl_exports);
351366 try self.writeSymbol(decl.link.macho.symbol_table_index.?);
352367
353368 const text_section = self.sections.items[self.text_section_index.?];
354369 const section_offset = symbol.n_value - text_section.addr;
355370 const file_offset = text_section.offset + section_offset;
356371 log.debug("file_offset 0x{x}\n", .{file_offset});
357 try self.base.file.?.pwriteAll(code, file_offset);
358372
359 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
360 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
361 return self.updateDeclExports(module, decl, decl_exports);
373 try self.base.file.?.pwriteAll(code, file_offset);
362374}
363375
364376pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {}
......@@ -374,7 +386,7 @@ pub fn updateDeclExports(
374386
375387 if (decl.link.macho.symbol_table_index == null) return;
376388
377 var decl_sym = self.symbol_table.items[decl.link.macho.symbol_table_index.?];
389 const decl_sym = &self.symbol_table.items[decl.link.macho.symbol_table_index.?];
378390 // TODO implement
379391 if (exports.len == 0) return;
380392
......@@ -488,9 +500,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
488500 const addr = blk: {
489501 if (self.last_text_block) |last| {
490502 const last_symbol = self.symbol_table.items[last.symbol_table_index.?];
491 const ideal_capacity = last.size * alloc_num / alloc_den;
492 const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity;
493 const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment);
503 const end_addr = last_symbol.n_value + last.size;
504 const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment);
494505 block_placement = last;
495506 break :blk new_start_addr;
496507 } else {
......@@ -504,10 +515,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
504515 const text_capacity = self.allocatedSize(text_section.offset);
505516 const needed_size = (addr + new_block_size) - text_section.addr;
506517 log.debug("text capacity 0x{x}, needed size 0x{x}\n", .{ text_capacity, needed_size });
507
508 if (needed_size > text_capacity) {
509 // TODO handle growth
510 }
518 assert(needed_size <= text_capacity); // TODO handle growth
511519
512520 self.last_text_block = text_block;
513521 text_section.size = needed_size;
......@@ -659,7 +667,7 @@ fn writeSymbol(self: *MachO, index: usize) !void {
659667 defer tracy.end();
660668
661669 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
662 var sym = [1]macho.nlist_64{self.symbol_table.items[index]};
670 const sym = [1]macho.nlist_64{self.symbol_table.items[index]};
663671 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
664672 log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off });
665673 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);