From 66a93ebfbf3724775ce56f91d74578c896fbfec5 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 14 Jun 2021 12:56:53 +0200 Subject: [PATCH 1/4] zld: clean up parsing section by type and attrs --- src/link/MachO/Object.zig | 37 +++++ src/link/MachO/Zld.zig | 337 ++++++++++++++++++++++++-------------- 2 files changed, 248 insertions(+), 126 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 4501d63fff..c4a044b446 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -70,6 +70,43 @@ pub const Section = struct { allocator.free(relocs); } } + + pub fn segname(self: Section) []const u8 { + return parseName(&self.inner.segname); + } + + pub fn sectname(self: Section) []const u8 { + return parseName(&self.inner.sectname); + } + + pub fn flags(self: Section) u32 { + return self.inner.flags; + } + + pub fn sectionType(self: Section) u8 { + return @truncate(u8, self.flags() & 0xff); + } + + pub fn sectionAttrs(self: Section) u32 { + return self.flags() & 0xffffff00; + } + + pub fn isCode(self: Section) bool { + const attr = self.sectionAttrs(); + return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 and attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0; + } + + pub fn isDebug(self: Section) bool { + return self.sectionAttrs() & macho.S_ATTR_DEBUG != 0; + } + + pub fn dontDeadStrip(self: Section) bool { + return self.sectionAttrs() & macho.S_ATTR_NO_DEAD_STRIP != 0; + } + + pub fn dontDeadStripIfReferencesLive(self: Section) bool { + return self.sectionAttrs() & macho.S_ATTR_LIVE_SUPPORT != 0; + } }; const DebugInfo = struct { diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 824ea1bb56..70f219bafd 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -409,7 +409,7 @@ fn mapAndUpdateSections( const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment); const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment); - log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{ + log.warn("{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), @@ -435,19 +435,17 @@ fn updateMetadata(self: *Zld) !void { const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; // Create missing metadata - for (object_seg.sections.items) |source_sect, sect_id| { - if (sect_id == object.text_section_index.?) continue; - const segname = parseName(&source_sect.segname); - const sectname = parseName(&source_sect.sectname); - const flags = source_sect.flags; + for (object.sections.items) |sect, sect_id| { + const segname = sect.segname(); + const sectname = sect.sectname(); - switch (flags) { - macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS => { - if (self.text_section_index != null) continue; + switch (sect.sectionType()) { + macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => { + if (self.text_const_section_index != null) continue; - self.text_section_index = @intCast(u16, text_seg.sections.items.len); + self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); try text_seg.addSection(self.allocator, .{ - .sectname = makeStaticString("__text"), + .sectname = makeStaticString("__const"), .segname = makeStaticString("__TEXT"), .addr = 0, .size = 0, @@ -455,70 +453,12 @@ fn updateMetadata(self: *Zld) !void { .@"align" = 0, .reloff = 0, .nreloc = 0, - .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, + .flags = macho.S_REGULAR, .reserved1 = 0, .reserved2 = 0, .reserved3 = 0, }); - }, - macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { - if (mem.eql(u8, segname, "__TEXT")) { - if (mem.eql(u8, sectname, "__ustring")) { - if (self.ustring_section_index != null) continue; - - self.ustring_section_index = @intCast(u16, text_seg.sections.items.len); - try text_seg.addSection(self.allocator, .{ - .sectname = makeStaticString("__ustring"), - .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, - }); - } else { - if (self.text_const_section_index != null) continue; - - self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); - try text_seg.addSection(self.allocator, .{ - .sectname = makeStaticString("__const"), - .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, - }); - } - } else if (mem.eql(u8, segname, "__DATA") or mem.eql(u8, segname, "__DATA_CONST")) { - if (self.data_const_section_index != null) continue; - - self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); - try data_const_seg.addSection(self.allocator, .{ - .sectname = makeStaticString("__const"), - .segname = makeStaticString("__DATA_CONST"), - .addr = 0, - .size = 0, - .offset = 0, - .@"align" = 0, - .reloff = 0, - .nreloc = 0, - .flags = macho.S_REGULAR, - .reserved1 = 0, - .reserved2 = 0, - .reserved3 = 0, - }); - } + continue; }, macho.S_CSTRING_LITERALS => { if (self.cstring_section_index != null) continue; @@ -538,6 +478,7 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); + continue; }, macho.S_MOD_INIT_FUNC_POINTERS => { if (self.mod_init_func_section_index != null) continue; @@ -557,6 +498,7 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); + continue; }, macho.S_MOD_TERM_FUNC_POINTERS => { if (self.mod_term_func_section_index != null) continue; @@ -576,6 +518,7 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); + continue; }, macho.S_ZEROFILL => { if (mem.eql(u8, sectname, "__common")) { @@ -615,6 +558,7 @@ fn updateMetadata(self: *Zld) !void { .reserved3 = 0, }); } + continue; }, macho.S_THREAD_LOCAL_VARIABLES => { if (self.tlv_section_index != null) continue; @@ -634,6 +578,7 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); + continue; }, macho.S_THREAD_LOCAL_REGULAR => { if (self.tlv_data_section_index != null) continue; @@ -653,6 +598,7 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); + continue; }, macho.S_THREAD_LOCAL_ZEROFILL => { if (self.tlv_bss_section_index != null) continue; @@ -672,58 +618,185 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); - }, - macho.S_COALESCED | - macho.S_ATTR_NO_TOC | - macho.S_ATTR_STRIP_STATIC_SYMS | - macho.S_ATTR_LIVE_SUPPORT => { - log.debug("TODO __eh_frame section: type 0x{x}, name '{s},{s}'", .{ - flags, segname, sectname, - }); continue; }, - macho.S_REGULAR | macho.S_ATTR_DEBUG => { - if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { - log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ - flags, segname, sectname, - }); - } - continue; - }, - else => { - if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) { - log.debug("TODO LLVM bitcode section: type 0x{x}, name '{s},{s}'", .{ - flags, segname, sectname, + 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, }); continue; } - log.err("unhandled section type 0x{x} for '{s},{s}'", .{ flags, segname, sectname }); - return error.UnhandledSection; }, + macho.S_REGULAR => { + if (sect.isCode()) { + if (self.text_section_index != null) continue; + + self.text_section_index = @intCast(u16, text_seg.sections.items.len); + try text_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__text"), + .segname = makeStaticString("__TEXT"), + .addr = 0, + .size = 0, + .offset = 0, + .@"align" = 0, + .reloff = 0, + .nreloc = 0, + .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, + }); + continue; + } + if (sect.isDebug()) { + if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { + log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ + sect.flags(), segname, sectname, + }); + } + continue; + } + + if (mem.eql(u8, segname, "__TEXT")) { + if (mem.eql(u8, sectname, "__ustring")) { + if (self.ustring_section_index != null) continue; + + self.ustring_section_index = @intCast(u16, text_seg.sections.items.len); + try text_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__ustring"), + .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, + }); + } else { + if (self.text_const_section_index != null) continue; + + self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); + try text_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__const"), + .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; + } + + if (mem.eql(u8, segname, "__DATA_CONST")) { + if (self.data_const_section_index != null) continue; + + self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); + try data_const_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__const"), + .segname = makeStaticString("__DATA_CONST"), + .addr = 0, + .size = 0, + .offset = 0, + .@"align" = 0, + .reloff = 0, + .nreloc = 0, + .flags = macho.S_REGULAR, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, + }); + continue; + } + + if (mem.eql(u8, segname, "__DATA")) { + if (mem.eql(u8, sectname, "__const")) { + if (self.data_const_section_index != null) continue; + + self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); + try data_const_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__const"), + .segname = makeStaticString("__DATA_CONST"), + .addr = 0, + .size = 0, + .offset = 0, + .@"align" = 0, + .reloff = 0, + .nreloc = 0, + .flags = macho.S_REGULAR, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, + }); + } else { + if (self.data_section_index != null) continue; + + self.data_section_index = @intCast(u16, data_seg.sections.items.len); + try data_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__data"), + .segname = makeStaticString("__DATA"), + .addr = 0, + .size = 0, + .offset = 0, + .@"align" = 0, + .reloff = 0, + .nreloc = 0, + .flags = macho.S_REGULAR, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, + }); + } + + continue; + } + + if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) { + log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{ + sect.flags(), segname, sectname, + }); + continue; + } + }, + else => {}, } + + log.err("{s}: unhandled section type 0x{x} for '{s},{s}'", .{ + object.name.?, + sect.flags(), + segname, + sectname, + }); + return error.UnhandledSection; } // Find ideal section alignment. - for (object_seg.sections.items) |source_sect| { - if (self.getMatchingSection(source_sect)) |res| { + for (object.sections.items) |sect| { + if (self.getMatchingSection(sect)) |res| { const target_seg = &self.load_commands.items[res.seg].Segment; const target_sect = &target_seg.sections.items[res.sect]; - target_sect.@"align" = math.max(target_sect.@"align", source_sect.@"align"); + target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align"); } } // Update section mappings - for (object_seg.sections.items) |source_sect, sect_id| { - const source_sect_id = @intCast(u16, sect_id); - if (self.getMatchingSection(source_sect)) |res| { - try self.mapAndUpdateSections(object, source_sect_id, res.seg, res.sect); + for (object.sections.items) |sect, sect_id| { + if (self.getMatchingSection(sect)) |res| { + try self.mapAndUpdateSections(object, @intCast(u16, sect_id), res.seg, res.sect); continue; } - - log.debug("section '{s},{s}' will be unmapped", .{ - parseName(&source_sect.segname), - parseName(&source_sect.sectname), - }); + log.warn("section '{s},{s}' will be unmapped", .{ sect.segname(), sect.sectname() }); } } @@ -819,13 +892,13 @@ const MatchingSection = struct { sect: u16, }; -fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection { - const segname = parseName(§ion.segname); - const sectname = parseName(§ion.sectname); +fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { + const segname = sect.segname(); + const sectname = sect.sectname(); const res: ?MatchingSection = blk: { - switch (section.flags) { - macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { + switch (sect.sectionType()) { + macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS, macho.S_LITERAL_POINTERS => { break :blk .{ .seg = self.text_segment_cmd_index.?, .sect = self.text_const_section_index.?, @@ -855,11 +928,12 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection { .seg = self.data_segment_cmd_index.?, .sect = self.common_section_index.?, }; + } else { + break :blk .{ + .seg = self.data_segment_cmd_index.?, + .sect = self.bss_section_index.?, + }; } - break :blk .{ - .seg = self.data_segment_cmd_index.?, - .sect = self.bss_section_index.?, - }; }, macho.S_THREAD_LOCAL_VARIABLES => { break :blk .{ @@ -879,31 +953,43 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection { .sect = self.tlv_bss_section_index.?, }; }, - macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS => { - break :blk .{ - .seg = self.text_segment_cmd_index.?, - .sect = self.text_section_index.?, - }; + macho.S_COALESCED => { + // TODO coalesced sections + break :blk null; }, macho.S_REGULAR => { + if (sect.isCode()) { + break :blk .{ + .seg = self.text_segment_cmd_index.?, + .sect = self.text_section_index.?, + }; + } + if (sect.isDebug()) { + // TODO debug attributes + break :blk null; + } + if (mem.eql(u8, segname, "__TEXT")) { if (mem.eql(u8, sectname, "__ustring")) { break :blk .{ .seg = self.text_segment_cmd_index.?, .sect = self.ustring_section_index.?, }; + } else { + break :blk .{ + .seg = self.text_segment_cmd_index.?, + .sect = self.text_const_section_index.?, + }; } - break :blk .{ - .seg = self.text_segment_cmd_index.?, - .sect = self.text_const_section_index.?, - }; } + if (mem.eql(u8, segname, "__DATA_CONST")) { break :blk .{ .seg = self.data_const_segment_cmd_index.?, .sect = self.data_const_section_index.?, }; } + if (mem.eql(u8, segname, "__DATA")) { if (mem.eql(u8, sectname, "__const")) { break :blk .{ @@ -916,11 +1002,10 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection { .sect = self.data_section_index.?, }; } + break :blk null; }, - else => { - break :blk null; - }, + else => break :blk null, } }; From 5fc25ee8e46e55a399216fc32a786ca7e4de55f7 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 14 Jun 2021 13:15:30 +0200 Subject: [PATCH 2/4] zld: handle __gcc_except_tab section --- src/link/MachO/Zld.zig | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 70f219bafd..68ed794377 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -65,6 +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, // __DATA_CONST segment sections got_section_index: ?u16 = null, @@ -649,6 +652,7 @@ fn updateMetadata(self: *Zld) !void { }); continue; } + if (sect.isDebug()) { if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ @@ -677,6 +681,24 @@ fn updateMetadata(self: *Zld) !void { .reserved2 = 0, .reserved3 = 0, }); + } else if (mem.eql(u8, sectname, "__gcc_except_tab")) { + if (self.gcc_except_tab != null) continue; + + self.gcc_except_tab = @intCast(u16, text_seg.sections.items.len); + try text_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__gcc_except_tab"), + .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, + }); } else { if (self.text_const_section_index != null) continue; @@ -975,6 +997,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { .seg = self.text_segment_cmd_index.?, .sect = self.ustring_section_index.?, }; + } else if (mem.eql(u8, sectname, "__gcc_except_tab")) { + break :blk .{ + .seg = self.text_segment_cmd_index.?, + .sect = self.gcc_except_tab.?, + }; } else { break :blk .{ .seg = self.text_segment_cmd_index.?, @@ -1031,6 +1058,7 @@ 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.cstring_section_index, &self.ustring_section_index, From 0ca0e884639bcd317e533735f3154ba27fc5934d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 14 Jun 2021 16:01:58 +0200 Subject: [PATCH 3/4] zld: handle __eh_frame section --- src/link/MachO/Zld.zig | 56 ++++++++++++++++++++++---------- src/link/MachO/reloc.zig | 2 ++ src/link/MachO/reloc/aarch64.zig | 43 ++++++++++++++++++++++-- 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}); From 7001bde84ce687885442a4d5a4f8715f7d573dba Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 14 Jun 2021 20:21:54 +0200 Subject: [PATCH 4/4] zld: map coalesced sections and handle undefines --- src/link/MachO/Zld.zig | 45 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 4820c03f6e..c0b5f03c58 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -646,6 +646,26 @@ fn updateMetadata(self: *Zld) !void { }); continue; } + + // TODO audit this: is this the right mapping? + if (self.data_const_section_index != null) continue; + + self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); + try data_const_seg.addSection(self.allocator, .{ + .sectname = makeStaticString("__const"), + .segname = makeStaticString("__DATA_CONST"), + .addr = 0, + .size = 0, + .offset = 0, + .@"align" = 0, + .reloff = 0, + .nreloc = 0, + .flags = macho.S_REGULAR, + .reserved1 = 0, + .reserved2 = 0, + .reserved3 = 0, + }); + continue; }, macho.S_REGULAR => { if (sect.isCode()) { @@ -999,7 +1019,10 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) ?MatchingSection { }; } - break :blk null; + break :blk .{ + .seg = self.data_const_segment_cmd_index.?, + .sect = self.data_const_section_index.?, + }; }, macho.S_REGULAR => { if (sect.isCode()) { @@ -2001,7 +2024,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { 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(); - args.target_addr = got.addr + final.got_index.? * @sizeOf(u64); + const got_index = final.got_index orelse { + // TODO remove this when we can link against TAPI files. + log.err("undefined reference to symbol '{s}'", .{final.name}); + log.err(" | referenced in {s}", .{ + rel.target.symbol.cast(Symbol.Unresolved).?.file.name.?, + }); + return error.UndefinedSymbolReference; + }; + args.target_addr = got.addr + got_index * @sizeOf(u64); }, else => |tt| { if (tt == .signed and rel.target == .section) { @@ -2067,7 +2098,15 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T log.debug(" | symbol stub '{s}'", .{sym.name}); const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; const stubs = segment.sections.items[self.stubs_section_index.?]; - break :blk stubs.addr + proxy.base.stubs_index.? * stubs.reserved2; + const stubs_index = proxy.base.stubs_index orelse { + // TODO remove this when we can link against TAPI files. + log.err("undefined reference to symbol '{s}'", .{final.name}); + log.err(" | referenced in {s}", .{ + sym.cast(Symbol.Unresolved).?.file.name.?, + }); + return error.UndefinedSymbolReference; + }; + break :blk stubs.addr + stubs_index * stubs.reserved2; } else { log.err("failed to resolve symbol '{s}' as a relocation target", .{sym.name}); return error.FailedToResolveRelocationTarget;