authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-24 20:32:09+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
log2cd84b1b3f0a6e3f030da723ec51f0be33b7a1ed
tree62a1ba0c73da431a27ef7b235a572f090a82a995
parentef5132c508f89ed8392143f6e8d03e8a2f121ba9

stage2 macho: refactor PIE generation on x86_64


2 files changed, 34 insertions(+), 40 deletions(-)

src/codegen.zig+2-2
...@@ -2773,7 +2773,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2773,7 +2773,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2773 // later in the linker.2773 // later in the linker.
2774 if (reg.id() == 0) { // %rax is special-cased2774 if (reg.id() == 0) { // %rax is special-cased
2775 try self.code.ensureCapacity(self.code.items.len + 5);2775 try self.code.ensureCapacity(self.code.items.len + 5);
2776 try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{2776 try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
2777 .address = x,2777 .address = x,
2778 .start = self.code.items.len,2778 .start = self.code.items.len,
2779 .len = 5,2779 .len = 5,
...@@ -2790,7 +2790,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2790,7 +2790,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2790 try self.code.ensureCapacity(self.code.items.len + 10);2790 try self.code.ensureCapacity(self.code.items.len + 10);
2791 // push %rax2791 // push %rax
2792 self.code.appendSliceAssumeCapacity(&[_]u8{0x50});2792 self.code.appendSliceAssumeCapacity(&[_]u8{0x50});
2793 try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{2793 try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
2794 .address = x,2794 .address = x,
2795 .start = self.code.items.len,2795 .start = self.code.items.len,
2796 .len = 5,2796 .len = 5,
src/link/MachO.zig+32-38
...@@ -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 of214 /// 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 code217 /// List of PIE fixups in the code.
218 /// This is a table of all RIP-relative positions that will need fixups218 /// 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-allocs220 pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{},
221 rip_positions: std.ArrayListUnmanaged(RipPosition) = .{},
222 /// Points to the previous and next neighbours221 /// Points to the previous and next neighbours
223 prev: ?*TextBlock,222 prev: ?*TextBlock,
224 next: ?*TextBlock,223 next: ?*TextBlock,
225224
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 };
239238
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 }
244242
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 }
248246
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}
851849
852pub fn deinit(self: *MachO) void {850pub 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 ignore894 // 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 }
10151017
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 }
10291027
...@@ -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;
11901186
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 {
12121208
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.?];
12201218
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 to1220 // 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 });
12261224
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 });
12411239
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)});
16591655
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 // ret1662 // 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 header1846 // 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 header1850 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}
18591853