aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-06-14 16:01:58 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-06-14 16:01:58 +0200
commit0ca0e884639bcd317e533735f3154ba27fc5934d (patch)
treec713d6ae48df5b0f5951e3cd825f458c5ec09ecd /src
parent5fc25ee8e46e55a399216fc32a786ca7e4de55f7 (diff)
downloadzig-0ca0e884639bcd317e533735f3154ba27fc5934d.tar.gz
zig-0ca0e884639bcd317e533735f3154ba27fc5934d.zip
zld: handle __eh_frame section
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO/Zld.zig56
-rw-r--r--src/link/MachO/reloc.zig2
-rw-r--r--src/link/MachO/reloc/aarch64.zig43
-rw-r--r--src/link/MachO/reloc/x86_64.zig8
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});