| author | |
| committer | |
| log | 7d487a41627658bfda37f1f06f8e453c2b576b9c |
| tree | e914dd539abbf953de3e15104492b52734688189 |
| parent | edc40157eb3b547f86185e2f85c08daf928eb9f1 |
| parent | edbfd04ec1fa11fde88166c4b906b7868cbbf218 |
| signature |
macho: fix bug where __text section would get overwritten2 files changed, 134 insertions(+), 23 deletions(-)
lib/std/macho.zig+110-7| ... | ... | @@ -647,6 +647,32 @@ pub const nlist_64 = extern struct { |
| 647 | 647 | n_value: u64, |
| 648 | 648 | }; |
| 649 | 649 | |
| 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. | |
| 656 | pub 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 | ||
| 650 | 676 | /// After MacOS X 10.1 when a new load command is added that is required to be |
| 651 | 677 | /// understood by the dynamic linker for the image to execute properly the |
| 652 | 678 | /// 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; |
| 1086 | 1112 | /// second stab entry with length information |
| 1087 | 1113 | pub const N_LENG = 0xfe; |
| 1088 | 1114 | |
| 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 | |
| 1127 | pub const S_NON_LAZY_SYMBOL_POINTERS = 0x6; | |
| 1128 | ||
| 1129 | /// section with only lazy symbol pointers | |
| 1130 | pub const S_LAZY_SYMBOL_POINTERS = 0x7; | |
| 1131 | ||
| 1132 | /// section with only symbol stubs, byte size of stub in the reserved2 field | |
| 1133 | pub const S_SYMBOL_STUBS = 0x8; | |
| 1134 | ||
| 1135 | /// section with only function pointers for initialization | |
| 1136 | pub const S_MOD_INIT_FUNC_POINTERS = 0x9; | |
| 1137 | ||
| 1138 | /// section with only function pointers for termination | |
| 1139 | pub const S_MOD_TERM_FUNC_POINTERS = 0xa; | |
| 1140 | ||
| 1141 | /// section contains symbols that are to be coalesced | |
| 1142 | pub const S_COALESCED = 0xb; | |
| 1143 | ||
| 1144 | /// zero fill on demand section (that can be larger than 4 gigabytes) | |
| 1145 | pub const S_GB_ZEROFILL = 0xc; | |
| 1146 | ||
| 1147 | /// section with only pairs of function pointers for interposing | |
| 1148 | pub const S_INTERPOSING = 0xd; | |
| 1149 | ||
| 1150 | /// section with only 16 byte literals | |
| 1151 | pub const S_16BYTE_LITERALS = 0xe; | |
| 1152 | ||
| 1153 | /// section contains DTrace Object Format | |
| 1154 | pub const S_DTRACE_DOF = 0xf; | |
| 1155 | ||
| 1156 | /// section with only lazy symbol pointers to lazy loaded dylibs | |
| 1157 | pub 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 | ||
| 1096 | 1167 | /// a debug section |
| 1097 | 1168 | pub const S_ATTR_DEBUG = 0x02000000; |
| 1098 | 1169 | |
| ... | ... | @@ -1154,3 +1225,35 @@ pub const VM_PROT_WRITE: vm_prot_t = 0x2; |
| 1154 | 1225 | |
| 1155 | 1226 | /// VM execute permission |
| 1156 | 1227 | pub const VM_PROT_EXECUTE: vm_prot_t = 0x4; |
| 1228 | ||
| 1229 | pub 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) { |
| 32 | 32 | .Dysymtab => |x| x.cmdsize, |
| 33 | 33 | }; |
| 34 | 34 | } |
| 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 | } | |
| 35 | 49 | }; |
| 36 | 50 | |
| 37 | 51 | base: File, |
| ... | ... | @@ -258,8 +272,7 @@ pub fn flush(self: *MachO, module: *Module) !void { |
| 258 | 272 | |
| 259 | 273 | var last_cmd_offset: usize = @sizeOf(macho.mach_header_64); |
| 260 | 274 | 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); | |
| 263 | 276 | last_cmd_offset += cmd.cmdsize(); |
| 264 | 277 | } |
| 265 | 278 | 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 { |
| 346 | 359 | .n_desc = 0, |
| 347 | 360 | .n_value = addr, |
| 348 | 361 | }; |
| 349 | self.offset_table.items[decl.link.macho.offset_table_index.?] = addr; | |
| 350 | 362 | |
| 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); | |
| 351 | 366 | try self.writeSymbol(decl.link.macho.symbol_table_index.?); |
| 352 | 367 | |
| 353 | 368 | const text_section = self.sections.items[self.text_section_index.?]; |
| 354 | 369 | const section_offset = symbol.n_value - text_section.addr; |
| 355 | 370 | const file_offset = text_section.offset + section_offset; |
| 356 | 371 | log.debug("file_offset 0x{x}\n", .{file_offset}); |
| 357 | try self.base.file.?.pwriteAll(code, file_offset); | |
| 358 | 372 | |
| 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); | |
| 362 | 374 | } |
| 363 | 375 | |
| 364 | 376 | pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {} |
| ... | ... | @@ -374,7 +386,7 @@ pub fn updateDeclExports( |
| 374 | 386 | |
| 375 | 387 | if (decl.link.macho.symbol_table_index == null) return; |
| 376 | 388 | |
| 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.?]; | |
| 378 | 390 | // TODO implement |
| 379 | 391 | if (exports.len == 0) return; |
| 380 | 392 | |
| ... | ... | @@ -488,9 +500,8 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 488 | 500 | const addr = blk: { |
| 489 | 501 | if (self.last_text_block) |last| { |
| 490 | 502 | 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); | |
| 494 | 505 | block_placement = last; |
| 495 | 506 | break :blk new_start_addr; |
| 496 | 507 | } else { |
| ... | ... | @@ -504,10 +515,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 504 | 515 | const text_capacity = self.allocatedSize(text_section.offset); |
| 505 | 516 | const needed_size = (addr + new_block_size) - text_section.addr; |
| 506 | 517 | 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 | |
| 511 | 519 | |
| 512 | 520 | self.last_text_block = text_block; |
| 513 | 521 | text_section.size = needed_size; |
| ... | ... | @@ -659,7 +667,7 @@ fn writeSymbol(self: *MachO, index: usize) !void { |
| 659 | 667 | defer tracy.end(); |
| 660 | 668 | |
| 661 | 669 | 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]}; | |
| 663 | 671 | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 664 | 672 | log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off }); |
| 665 | 673 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); |