| ... | ... | @@ -214,16 +214,15 @@ pub const TextBlock = struct { |
| 214 | 214 | /// Unlike in Elf, we need to store the size of this symbol as part of |
| 215 | 215 | /// the TextBlock since macho.nlist_64 lacks this information. |
| 216 | 216 | size: u64, |
| 217 | | /// List of RIP-relative positions in the code |
| 218 | | /// This is a table of all RIP-relative positions that will need fixups |
| 217 | /// List of PIE fixups in the code. |
| 218 | /// This is a table of all position-relative positions that will need fixups |
| 219 | 219 | /// after codegen when linker assigns addresses to GOT entries. |
| 220 | | /// TODO handle freeing, shrinking and re-allocs |
| 221 | | rip_positions: std.ArrayListUnmanaged(RipPosition) = .{}, |
| 220 | pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 222 | 221 | /// Points to the previous and next neighbours |
| 223 | 222 | prev: ?*TextBlock, |
| 224 | 223 | next: ?*TextBlock, |
| 225 | 224 | |
| 226 | | pub const RipPosition = struct { |
| 225 | pub const PieFixup = struct { |
| 227 | 226 | address: u64, |
| 228 | 227 | start: usize, |
| 229 | 228 | len: usize, |
| ... | ... | @@ -237,13 +236,12 @@ pub const TextBlock = struct { |
| 237 | 236 | .next = null, |
| 238 | 237 | }; |
| 239 | 238 | |
| 240 | | pub fn addRipPosition(self: *TextBlock, alloc: *Allocator, rip: RipPosition) !void { |
| 241 | | std.debug.print("text_block={}, rip={}\n", .{ self.local_sym_index, rip }); |
| 242 | | return self.rip_positions.append(alloc, rip); |
| 239 | pub fn addPieFixup(self: *TextBlock, alloc: *Allocator, fixup: PieFixup) !void { |
| 240 | return self.pie_fixups.append(alloc, fixup); |
| 243 | 241 | } |
| 244 | 242 | |
| 245 | 243 | fn deinit(self: *TextBlock, alloc: *Allocator) void { |
| 246 | | self.rip_positions.deinit(alloc); |
| 244 | self.pie_fixups.deinit(alloc); |
| 247 | 245 | } |
| 248 | 246 | |
| 249 | 247 | /// Returns how much room there is to grow in virtual address space. |
| ... | ... | @@ -850,6 +848,9 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 { |
| 850 | 848 | } |
| 851 | 849 | |
| 852 | 850 | pub fn deinit(self: *MachO) void { |
| 851 | for (self.text_block_free_list.items) |tb| { |
| 852 | tb.deinit(self.base.allocator); |
| 853 | } |
| 853 | 854 | self.text_block_free_list.deinit(self.base.allocator); |
| 854 | 855 | self.offset_table.deinit(self.base.allocator); |
| 855 | 856 | self.offset_table_free_list.deinit(self.base.allocator); |
| ... | ... | @@ -892,7 +893,9 @@ fn freeTextBlock(self: *MachO, text_block: *TextBlock) void { |
| 892 | 893 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { |
| 893 | 894 | // The free list is heuristics, it doesn't have to be perfect, so we can ignore |
| 894 | 895 | // the OOM here. |
| 895 | | self.text_block_free_list.append(self.base.allocator, prev) catch {}; |
| 896 | self.text_block_free_list.append(self.base.allocator, prev) catch { |
| 897 | prev.deinit(self.base.allocator); |
| 898 | }; |
| 896 | 899 | } |
| 897 | 900 | } else { |
| 898 | 901 | text_block.prev = null; |
| ... | ... | @@ -982,7 +985,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 982 | 985 | log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, symbol.n_value, vaddr }); |
| 983 | 986 | if (vaddr != symbol.n_value) { |
| 984 | 987 | symbol.n_value = vaddr; |
| 985 | | |
| 986 | 988 | log.debug(" (writing new offset table entry)\n", .{}); |
| 987 | 989 | self.offset_table.items[decl.link.macho.offset_table_index] = vaddr; |
| 988 | 990 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| ... | ... | @@ -1013,17 +1015,13 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1013 | 1015 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1014 | 1016 | } |
| 1015 | 1017 | |
| 1016 | | // Perform RIP-relative fixups (if any) |
| 1018 | // Perform PIE fixups (if any) |
| 1017 | 1019 | const got_section = self.sections.items[self.got_section_index.?]; |
| 1018 | | for (decl.link.macho.rip_positions.items) |rip| { |
| 1019 | | std.debug.print("rip={}\n", .{rip}); |
| 1020 | | const target_addr = rip.address; |
| 1021 | | // const got_addr = got_section.addr + decl.link.macho.offset_table_index * @sizeOf(u64); |
| 1022 | | const this_addr = symbol.n_value + rip.start; |
| 1023 | | std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{ target_addr, this_addr }); |
| 1024 | | const displacement = @intCast(u32, target_addr - this_addr - rip.len); |
| 1025 | | std.debug.print("displacement=0x{x}\n", .{displacement}); |
| 1026 | | var placeholder = code_buffer.items[rip.start + rip.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; |
| 1020 | while (decl.link.macho.pie_fixups.popOrNull()) |fixup| { |
| 1021 | const target_addr = fixup.address; |
| 1022 | const this_addr = symbol.n_value + fixup.start; |
| 1023 | const displacement = @intCast(u32, target_addr - this_addr - fixup.len); |
| 1024 | var placeholder = code_buffer.items[fixup.start + fixup.len - @sizeOf(u32) ..][0..@sizeOf(u32)]; |
| 1027 | 1025 | mem.writeIntSliceLittle(u32, placeholder, displacement); |
| 1028 | 1026 | } |
| 1029 | 1027 | |
| ... | ... | @@ -1185,8 +1183,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1185 | 1183 | if (self.text_section_index == null) { |
| 1186 | 1184 | self.text_section_index = @intCast(u16, self.sections.items.len); |
| 1187 | 1185 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1188 | | text_segment.cmdsize += @sizeOf(macho.section_64); |
| 1189 | | text_segment.nsects += 1; |
| 1190 | 1186 | |
| 1191 | 1187 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 1192 | 1188 | const file_size = mem.alignForwardGeneric(u64, program_code_size_hint, self.page_size); |
| ... | ... | @@ -1212,11 +1208,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1212 | 1208 | |
| 1213 | 1209 | text_segment.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section. |
| 1214 | 1210 | text_segment.filesize = file_size + off; |
| 1211 | text_segment.cmdsize += @sizeOf(macho.section_64); |
| 1212 | text_segment.nsects += 1; |
| 1215 | 1213 | self.cmd_table_dirty = true; |
| 1216 | 1214 | } |
| 1217 | 1215 | if (self.got_section_index == null) { |
| 1218 | | const text_section = &self.sections.items[self.text_section_index.?]; |
| 1219 | 1216 | self.got_section_index = @intCast(u16, self.sections.items.len); |
| 1217 | const text_section = &self.sections.items[self.text_section_index.?]; |
| 1220 | 1218 | |
| 1221 | 1219 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1222 | 1220 | // TODO looking for free space should be done *within* a segment it belongs to |
| ... | ... | @@ -1225,7 +1223,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1225 | 1223 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1226 | 1224 | |
| 1227 | 1225 | try self.sections.append(self.base.allocator, .{ |
| 1228 | | .sectname = makeStaticString("__ziggot"), |
| 1226 | .sectname = makeStaticString("__got"), |
| 1229 | 1227 | .segname = makeStaticString("__TEXT"), |
| 1230 | 1228 | .addr = text_section.addr + text_section.size, |
| 1231 | 1229 | .size = file_size, |
| ... | ... | @@ -1239,8 +1237,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1239 | 1237 | .reserved3 = 0, |
| 1240 | 1238 | }); |
| 1241 | 1239 | |
| 1242 | | const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1243 | 1240 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1241 | const added_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1244 | 1242 | text_segment.vmsize += added_size; |
| 1245 | 1243 | text_segment.filesize += added_size; |
| 1246 | 1244 | text_segment.cmdsize += @sizeOf(macho.section_64); |
| ... | ... | @@ -1653,18 +1651,17 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1653 | 1651 | const off = sect.offset + @sizeOf(u64) * index; |
| 1654 | 1652 | const vmaddr = sect.addr + @sizeOf(u64) * index; |
| 1655 | 1653 | const pos_symbol_off = @truncate(u31, vmaddr - self.offset_table.items[index] + 7); |
| 1656 | | const symbol_off = @intCast(i32, pos_symbol_off) * -1; |
| 1657 | | std.debug.print("vmaddr=0x{x},item=0x{x}\n", .{vmaddr, self.offset_table.items[index]}); |
| 1658 | | std.debug.print("posSymbolOff=0x{x},symbolOff=0x{x}\n", .{pos_symbol_off, @bitCast(u32, symbol_off)}); |
| 1654 | const symbol_off = @bitCast(u32, @intCast(i32, pos_symbol_off) * -1); |
| 1659 | 1655 | |
| 1660 | 1656 | var code: [8]u8 = undefined; |
| 1661 | 1657 | // lea %rax, [rip - disp] |
| 1662 | 1658 | code[0] = 0x48; |
| 1663 | 1659 | code[1] = 0x8D; |
| 1664 | 1660 | code[2] = 0x5; |
| 1665 | | mem.writeInt(u32, code[3..7], @bitCast(u32, symbol_off), endian); |
| 1661 | mem.writeInt(u32, code[3..7], symbol_off, endian); |
| 1666 | 1662 | // ret |
| 1667 | 1663 | code[7] = 0xC3; |
| 1664 | |
| 1668 | 1665 | log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off }); |
| 1669 | 1666 | try self.base.file.?.pwriteAll(&code, off); |
| 1670 | 1667 | } |
| ... | ... | @@ -1846,14 +1843,11 @@ fn writeCmdHeaders(self: *MachO) !void { |
| 1846 | 1843 | // only one, noname segment to append this section header to. |
| 1847 | 1844 | return error.TODOImplementWritingObjFiles; |
| 1848 | 1845 | }; |
| 1849 | | // write __text section header |
| 1850 | | const id1 = self.text_section_index.?; |
| 1851 | | log.debug("writing text section header at 0x{x}\n", .{off}); |
| 1852 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id1 .. id1 + 1]), off); |
| 1853 | | // write __ziggot section header |
| 1854 | | const id2 = self.got_section_index.?; |
| 1855 | | log.debug("writing got section header at 0x{x}\n", .{off + @sizeOf(macho.section_64)}); |
| 1856 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id2 .. id2 + 1]), off + @sizeOf(macho.section_64)); |
| 1846 | // write sections belonging to __TEXT segment |
| 1847 | // TODO section indices should belong to each Segment, and we should iterate dynamically. |
| 1848 | const id = self.text_section_index.?; |
| 1849 | log.debug("writing __TEXT section headers at 0x{x}\n", .{off}); |
| 1850 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[id .. id + 2]), off); |
| 1857 | 1851 | } |
| 1858 | 1852 | } |
| 1859 | 1853 | |