diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-14 16:01:58 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-15 12:14:04 +0200 |
| commit | cf26f8c19b2e39a8279360bd4c93e38d4dc6b4d0 (patch) | |
| tree | 662ca49489bda999d907a4d0f7e6a7151d88686b | |
| parent | 15ff0db794c92dd64c7b585fb5eed1adb4888c5e (diff) | |
| download | zig-cf26f8c19b2e39a8279360bd4c93e38d4dc6b4d0.tar.gz zig-cf26f8c19b2e39a8279360bd4c93e38d4dc6b4d0.zip | |
zld: handle __eh_frame section
| -rw-r--r-- | src/link/MachO/Zld.zig | 56 | ||||
| -rw-r--r-- | src/link/MachO/reloc.zig | 2 | ||||
| -rw-r--r-- | src/link/MachO/reloc/aarch64.zig | 43 | ||||
| -rw-r--r-- | src/link/MachO/reloc/x86_64.zig | 8 |
4 files changed, 87 insertions, 22 deletions
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 68ed794377..4820c03f6e 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -65,9 +65,9 @@ stub_helper_section_index: ?u16 = null, text_const_section_index: ?u16 = null, cstring_section_index: ?u16 = null, ustring_section_index: ?u16 = null, -gcc_except_tab: ?u16 = null, -unwind_info: ?u16 = null, -eh_frame: ?u16 = null, +gcc_except_tab_section_index: ?u16 = null, +unwind_info_section_index: ?u16 = null, +eh_frame_section_index: ?u16 = null, // __DATA_CONST segment sections got_section_index: ?u16 = null, @@ -412,7 +412,7 @@ fn mapAndUpdateSections( const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment); const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment); - log.warn("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{ + log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{ object.name.?, parseName(&source_sect.inner.segname), parseName(&source_sect.inner.sectname), @@ -625,8 +625,24 @@ fn updateMetadata(self: *Zld) !void { }, macho.S_COALESCED => { if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) { - log.debug("TODO __eh_frame section: type 0x{x}, name '{s},{s}'", .{ - sect.flags(), segname, sectname, + // TODO I believe __eh_frame is currently part of __unwind_info section + // in the latest ld64 output. + if (self.eh_frame_section_index != null) continue; + + self.eh_frame_section_index = @intCast(u16, text_seg.sections.items.len); + try text_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__eh_frame"), + .segname = makeStaticString("__TEXT"), + .addr = 0, + .size = 0, + .offset = 0, + .@"align" = 0, + .reloff = 0, + .nreloc = 0, + .flags = macho.S_REGULAR, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, }); continue; } @@ -682,9 +698,9 @@ fn updateMetadata(self: *Zld) !void { .reserved3 = 0, }); } else if (mem.eql(u8, sectname, "__gcc_except_tab")) { - if (self.gcc_except_tab != null) continue; + if (self.gcc_except_tab_section_index != null) continue; - self.gcc_except_tab = @intCast(u16, text_seg.sections.items.len); + self.gcc_except_tab_section_index = @intCast(u16, text_seg.sections.items.len); try text_seg.addSection(self.allocator, .{ .sectname = makeStaticString("__gcc_except_tab"), .segname = makeStaticString("__TEXT"), @@ -818,7 +834,7 @@ fn updateMetadata(self: *Zld) !void { try self.mapAndUpdateSections(object, @intCast(u16, sect_id), res.seg, res.sect); continue; } - log.warn("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() }); + log.debug("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() }); } } @@ -976,7 +992,13 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { }; }, macho.S_COALESCED => { - // TODO coalesced sections + if (mem.eql(u8, "__TEXT", segname) and mem.eql(u8, "__eh_frame", sectname)) { + break :blk .{ + .seg = self.text_segment_cmd_index.?, + .sect = self.eh_frame_section_index.?, + }; + } + break :blk null; }, macho.S_REGULAR => { @@ -1000,7 +1022,7 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { } else if (mem.eql(u8, sectname, "__gcc_except_tab")) { break :blk .{ .seg = self.text_segment_cmd_index.?, - .sect = self.gcc_except_tab.?, + .sect = self.gcc_except_tab_section_index.?, }; } else { break :blk .{ @@ -1058,10 +1080,11 @@ fn sortSections(self: *Zld) !void { &self.text_section_index, &self.stubs_section_index, &self.stub_helper_section_index, - &self.gcc_except_tab, - &self.text_const_section_index, + &self.gcc_except_tab_section_index, &self.cstring_section_index, &self.ustring_section_index, + &self.text_const_section_index, + &self.eh_frame_section_index, }; for (indices) |maybe_index| { const new_index: u16 = if (maybe_index.*) |index| blk: { @@ -1846,7 +1869,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { for (relocs) |rel| { switch (rel.@"type") { .unsigned => continue, - .got_page, .got_page_off, .got_load, .got => { + .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { const sym = rel.target.symbol.getTopmostAlias(); if (sym.got_index != null) continue; @@ -1864,9 +1887,6 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { if (sym.stubs_index != null) continue; if (sym.@"type" != .proxy) continue; - // if (sym.cast(Symbol.Regular)) |reg| { - // if (!reg.weak_ref) continue; - // } const index = @intCast(u32, self.stubs.items.len); sym.stubs_index = index; @@ -1977,7 +1997,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { }); } }, - .got_page, .got_page_off, .got_load, .got => { + .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; const got = dc_seg.sections.items[self.got_section_index.?]; const final = rel.target.symbol.getTopmostAlias(); diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index 59aff74a83..1e1b938196 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -52,6 +52,7 @@ pub const Relocation = struct { .page_off => @fieldParentPtr(aarch64.PageOff, "base", base).resolve(args), .got_page => @fieldParentPtr(aarch64.GotPage, "base", base).resolve(args), .got_page_off => @fieldParentPtr(aarch64.GotPageOff, "base", base).resolve(args), + .pointer_to_got => @fieldParentPtr(aarch64.PointerToGot, "base", base).resolve(args), .tlvp_page => @fieldParentPtr(aarch64.TlvpPage, "base", base).resolve(args), .tlvp_page_off => @fieldParentPtr(aarch64.TlvpPageOff, "base", base).resolve(args), .branch_x86_64 => @fieldParentPtr(x86_64.Branch, "base", base).resolve(args), @@ -70,6 +71,7 @@ pub const Relocation = struct { got_page, got_page_off, tlvp_page, + pointer_to_got, tlvp_page_off, branch_x86_64, signed, diff --git a/src/link/MachO/reloc/aarch64.zig b/src/link/MachO/reloc/aarch64.zig index c4b3104879..16b982bf90 100644 --- a/src/link/MachO/reloc/aarch64.zig +++ b/src/link/MachO/reloc/aarch64.zig @@ -141,6 +141,20 @@ pub const GotPageOff = struct { } }; +pub const PointerToGot = struct { + base: Relocation, + + pub const base_type: Relocation.Type = .pointer_to_got; + + pub fn resolve(ptr_to_got: PointerToGot, args: Relocation.ResolveArgs) !void { + const result = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr)); + + log.debug(" | calculated value 0x{x}", .{result}); + + mem.writeIntLittle(u32, ptr_to_got.base.code[0..4], @bitCast(u32, result)); + } +}; + pub const TlvpPage = struct { base: Relocation, /// Always .PCRelativeAddress @@ -228,9 +242,7 @@ pub const Parser = struct { try parser.parseTlvpLoadPageOff(rel); }, .ARM64_RELOC_POINTER_TO_GOT => { - // TODO Handle pointer to GOT. This reloc seems to appear in - // __LD,__compact_unwind section which we currently don't handle. - log.debug("Unhandled relocation ARM64_RELOC_POINTER_TO_GOT", .{}); + try parser.parsePointerToGot(rel); }, } } @@ -583,6 +595,31 @@ pub const Parser = struct { log.debug(" | emitting {}", .{unsigned}); try parser.parsed.append(&unsigned.base); } + + fn parsePointerToGot(parser: *Parser, rel: macho.relocation_info) !void { + const rel_type = @intToEnum(macho.reloc_type_arm64, rel.r_type); + assert(rel_type == .ARM64_RELOC_POINTER_TO_GOT); + assert(rel.r_pcrel == 1); + assert(rel.r_length == 2); + + var ptr_to_got = try parser.allocator.create(PointerToGot); + errdefer parser.allocator.destroy(ptr_to_got); + + const target = Relocation.Target.from_reloc(rel, parser.symbols); + const offset = @intCast(u32, rel.r_address); + + ptr_to_got.* = .{ + .base = .{ + .@"type" = .pointer_to_got, + .code = parser.code[offset..][0..4], + .offset = offset, + .target = target, + }, + }; + + log.debug(" | emitting {}", .{ptr_to_got}); + try parser.parsed.append(&ptr_to_got.base); + } }; inline fn isArithmeticOp(inst: *const [4]u8) bool { diff --git a/src/link/MachO/reloc/x86_64.zig b/src/link/MachO/reloc/x86_64.zig index a5e3ff2825..2a457fdea2 100644 --- a/src/link/MachO/reloc/x86_64.zig +++ b/src/link/MachO/reloc/x86_64.zig @@ -66,11 +66,15 @@ pub const GotLoad = struct { pub const Got = struct { base: Relocation, + addend: i32, pub const base_type: Relocation.Type = .got; pub fn resolve(got: Got, args: Relocation.ResolveArgs) !void { - const displacement = try math.cast(i32, @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4); + const displacement = try math.cast( + i32, + @intCast(i64, args.target_addr) - @intCast(i64, args.source_addr) - 4 + got.addend, + ); log.debug(" | displacement 0x{x}", .{displacement}); mem.writeIntLittle(u32, got.base.code[0..4], @bitCast(u32, displacement)); } @@ -237,6 +241,7 @@ pub const Parser = struct { const offset = @intCast(u32, rel.r_address); const inst = parser.code[offset..][0..4]; const target = Relocation.Target.from_reloc(rel, parser.symbols); + const addend = mem.readIntLittle(i32, inst); var got = try parser.allocator.create(Got); errdefer parser.allocator.destroy(got); @@ -248,6 +253,7 @@ pub const Parser = struct { .offset = offset, .target = target, }, + .addend = addend, }; log.debug(" | emitting {}", .{got}); |
