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