Commit 04659f5b82
Changed files (1)
src
link
MachO
src/link/MachO/Zld.zig
@@ -78,14 +78,9 @@ undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
externs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
-// locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{},
-// exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},
-// nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
-// lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
-// tlv_bootstrap: ?Import = null,
-// threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
-// local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
-// nonlazy_pointers: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
+threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
+rebases: std.ArrayListUnmanaged(Pointer) = .{},
+got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
stub_helper_stubs_start_off: ?u64 = null,
@@ -279,12 +274,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
try self.populateMetadata();
try self.parseInputFiles(files);
try self.resolveSymbols();
- self.printSymtab();
- // try self.sortSections();
- // try self.allocateTextSegment();
- // try self.allocateDataConstSegment();
- // try self.allocateDataSegment();
- // self.allocateLinkeditSegment();
+ try self.updateMetadata();
+ try self.sortSections();
+ try self.allocateTextSegment();
+ try self.allocateDataConstSegment();
+ try self.allocateDataSegment();
+ self.allocateLinkeditSegment();
// try self.writeStubHelperCommon();
// try self.doRelocs();
// try self.flush();
@@ -403,28 +398,69 @@ fn mapAndUpdateSections(
target_sect.size = offset + size;
}
-fn updateMetadata(self: *Zld, object_id: u16) !void {
- const object = self.objects.items[object_id];
- const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
- const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
- const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
- const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
-
- // Create missing metadata
- for (object_seg.sections.items) |source_sect, id| {
- if (id == object.text_section_index.?) continue;
- const segname = parseName(&source_sect.segname);
- const sectname = parseName(&source_sect.sectname);
- const flags = source_sect.flags;
-
- switch (flags) {
- macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
- if (mem.eql(u8, segname, "__TEXT")) {
- if (self.text_const_section_index != null) continue;
+fn updateMetadata(self: *Zld) !void {
+ for (self.objects.items) |object, id| {
+ const object_id = @intCast(u16, id);
+ const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
+ const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
+ const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
- self.text_const_section_index = @intCast(u16, text_seg.sections.items.len);
+ // 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;
+
+ switch (flags) {
+ macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
+ if (mem.eql(u8, segname, "__TEXT")) {
+ 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")) {
+ if (!mem.eql(u8, sectname, "__const")) continue;
+ 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,
+ });
+ }
+ },
+ macho.S_CSTRING_LITERALS => {
+ if (!mem.eql(u8, segname, "__TEXT")) continue;
+ if (self.cstring_section_index != null) continue;
+
+ self.cstring_section_index = @intCast(u16, text_seg.sections.items.len);
try text_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__const"),
+ .sectname = makeStaticString("__cstring"),
.segname = makeStaticString("__TEXT"),
.addr = 0,
.size = 0,
@@ -432,18 +468,19 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
- .flags = macho.S_REGULAR,
+ .flags = macho.S_CSTRING_LITERALS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
- } else if (mem.eql(u8, segname, "__DATA")) {
- if (!mem.eql(u8, sectname, "__const")) continue;
- if (self.data_const_section_index != null) continue;
+ },
+ macho.S_MOD_INIT_FUNC_POINTERS => {
+ if (!mem.eql(u8, segname, "__DATA")) continue;
+ if (self.mod_init_func_section_index != null) continue;
- self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len);
+ self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
try data_const_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__const"),
+ .sectname = makeStaticString("__mod_init_func"),
.segname = makeStaticString("__DATA_CONST"),
.addr = 0,
.size = 0,
@@ -451,183 +488,143 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {
.@"align" = 0,
.reloff = 0,
.nreloc = 0,
- .flags = macho.S_REGULAR,
+ .flags = macho.S_MOD_INIT_FUNC_POINTERS,
.reserved1 = 0,
.reserved2 = 0,
.reserved3 = 0,
});
- }
- },
- macho.S_CSTRING_LITERALS => {
- if (!mem.eql(u8, segname, "__TEXT")) continue;
- if (self.cstring_section_index != null) continue;
-
- self.cstring_section_index = @intCast(u16, text_seg.sections.items.len);
- try text_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__cstring"),
- .segname = makeStaticString("__TEXT"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_CSTRING_LITERALS,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- macho.S_MOD_INIT_FUNC_POINTERS => {
- if (!mem.eql(u8, segname, "__DATA")) continue;
- if (self.mod_init_func_section_index != null) continue;
-
- self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
- try data_const_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__mod_init_func"),
- .segname = makeStaticString("__DATA_CONST"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_MOD_INIT_FUNC_POINTERS,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- macho.S_MOD_TERM_FUNC_POINTERS => {
- if (!mem.eql(u8, segname, "__DATA")) continue;
- if (self.mod_term_func_section_index != null) continue;
-
- self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
- try data_const_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__mod_term_func"),
- .segname = makeStaticString("__DATA_CONST"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_MOD_TERM_FUNC_POINTERS,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- macho.S_ZEROFILL => {
- if (!mem.eql(u8, segname, "__DATA")) continue;
- if (self.bss_section_index != null) continue;
-
- self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
- try data_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__bss"),
- .segname = makeStaticString("__DATA"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_ZEROFILL,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- macho.S_THREAD_LOCAL_VARIABLES => {
- if (!mem.eql(u8, segname, "__DATA")) continue;
- if (self.tlv_section_index != null) continue;
-
- self.tlv_section_index = @intCast(u16, data_seg.sections.items.len);
- try data_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__thread_vars"),
- .segname = makeStaticString("__DATA"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_THREAD_LOCAL_VARIABLES,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- macho.S_THREAD_LOCAL_REGULAR => {
- if (!mem.eql(u8, segname, "__DATA")) continue;
- if (self.tlv_data_section_index != null) continue;
-
- self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len);
- try data_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__thread_data"),
- .segname = makeStaticString("__DATA"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_THREAD_LOCAL_REGULAR,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- macho.S_THREAD_LOCAL_ZEROFILL => {
- if (!mem.eql(u8, segname, "__DATA")) continue;
- if (self.tlv_bss_section_index != null) continue;
-
- self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len);
- try data_seg.addSection(self.allocator, .{
- .sectname = makeStaticString("__thread_bss"),
- .segname = makeStaticString("__DATA"),
- .addr = 0,
- .size = 0,
- .offset = 0,
- .@"align" = 0,
- .reloff = 0,
- .nreloc = 0,
- .flags = macho.S_THREAD_LOCAL_ZEROFILL,
- .reserved1 = 0,
- .reserved2 = 0,
- .reserved3 = 0,
- });
- },
- else => {
- log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname });
- },
- }
- }
+ },
+ macho.S_MOD_TERM_FUNC_POINTERS => {
+ if (!mem.eql(u8, segname, "__DATA")) continue;
+ if (self.mod_term_func_section_index != null) continue;
- // Find ideal section alignment.
- for (object_seg.sections.items) |source_sect, id| {
- if (self.getMatchingSection(source_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");
+ self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
+ try data_const_seg.addSection(self.allocator, .{
+ .sectname = makeStaticString("__mod_term_func"),
+ .segname = makeStaticString("__DATA_CONST"),
+ .addr = 0,
+ .size = 0,
+ .offset = 0,
+ .@"align" = 0,
+ .reloff = 0,
+ .nreloc = 0,
+ .flags = macho.S_MOD_TERM_FUNC_POINTERS,
+ .reserved1 = 0,
+ .reserved2 = 0,
+ .reserved3 = 0,
+ });
+ },
+ macho.S_ZEROFILL => {
+ if (!mem.eql(u8, segname, "__DATA")) continue;
+ if (self.bss_section_index != null) continue;
+
+ self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
+ try data_seg.addSection(self.allocator, .{
+ .sectname = makeStaticString("__bss"),
+ .segname = makeStaticString("__DATA"),
+ .addr = 0,
+ .size = 0,
+ .offset = 0,
+ .@"align" = 0,
+ .reloff = 0,
+ .nreloc = 0,
+ .flags = macho.S_ZEROFILL,
+ .reserved1 = 0,
+ .reserved2 = 0,
+ .reserved3 = 0,
+ });
+ },
+ macho.S_THREAD_LOCAL_VARIABLES => {
+ if (!mem.eql(u8, segname, "__DATA")) continue;
+ if (self.tlv_section_index != null) continue;
+
+ self.tlv_section_index = @intCast(u16, data_seg.sections.items.len);
+ try data_seg.addSection(self.allocator, .{
+ .sectname = makeStaticString("__thread_vars"),
+ .segname = makeStaticString("__DATA"),
+ .addr = 0,
+ .size = 0,
+ .offset = 0,
+ .@"align" = 0,
+ .reloff = 0,
+ .nreloc = 0,
+ .flags = macho.S_THREAD_LOCAL_VARIABLES,
+ .reserved1 = 0,
+ .reserved2 = 0,
+ .reserved3 = 0,
+ });
+ },
+ macho.S_THREAD_LOCAL_REGULAR => {
+ if (!mem.eql(u8, segname, "__DATA")) continue;
+ if (self.tlv_data_section_index != null) continue;
+
+ self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len);
+ try data_seg.addSection(self.allocator, .{
+ .sectname = makeStaticString("__thread_data"),
+ .segname = makeStaticString("__DATA"),
+ .addr = 0,
+ .size = 0,
+ .offset = 0,
+ .@"align" = 0,
+ .reloff = 0,
+ .nreloc = 0,
+ .flags = macho.S_THREAD_LOCAL_REGULAR,
+ .reserved1 = 0,
+ .reserved2 = 0,
+ .reserved3 = 0,
+ });
+ },
+ macho.S_THREAD_LOCAL_ZEROFILL => {
+ if (!mem.eql(u8, segname, "__DATA")) continue;
+ if (self.tlv_bss_section_index != null) continue;
+
+ self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len);
+ try data_seg.addSection(self.allocator, .{
+ .sectname = makeStaticString("__thread_bss"),
+ .segname = makeStaticString("__DATA"),
+ .addr = 0,
+ .size = 0,
+ .offset = 0,
+ .@"align" = 0,
+ .reloff = 0,
+ .nreloc = 0,
+ .flags = macho.S_THREAD_LOCAL_ZEROFILL,
+ .reserved1 = 0,
+ .reserved2 = 0,
+ .reserved3 = 0,
+ });
+ },
+ else => {
+ log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname });
+ },
+ }
}
- }
- // Update section mappings
- for (object_seg.sections.items) |source_sect, id| {
- const source_sect_id = @intCast(u16, id);
- if (self.getMatchingSection(source_sect)) |res| {
- try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect);
- continue;
+ // Find ideal section alignment.
+ for (object_seg.sections.items) |source_sect| {
+ if (self.getMatchingSection(source_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");
+ }
}
- const segname = parseName(&source_sect.segname);
- const sectname = parseName(&source_sect.sectname);
- log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });
- try self.unhandled_sections.putNoClobber(self.allocator, .{
- .object_id = object_id,
- .source_sect_id = source_sect_id,
- }, 0);
+ // 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_id, source_sect_id, res.seg, res.sect);
+ continue;
+ }
+
+ const segname = parseName(&source_sect.segname);
+ const sectname = parseName(&source_sect.sectname);
+ log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });
+ try self.unhandled_sections.putNoClobber(self.allocator, .{
+ .object_id = object_id,
+ .source_sect_id = source_sect_id,
+ }, 0);
+ }
}
}
@@ -826,7 +823,10 @@ fn sortSections(self: *Zld) !void {
fn allocateTextSegment(self: *Zld) !void {
const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
- const nexterns = @intCast(u32, self.lazy_imports.items().len);
+ // TODO This should be worked out by scanning the relocations in the __text sections of all combined
+ // object files. For the time being, assume all externs are stubs (this is wasting space but should
+ // correspond to the worst-case upper bound).
+ const nstubs = @intCast(u32, self.externs.count());
const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
seg.inner.fileoff = 0;
@@ -835,14 +835,14 @@ fn allocateTextSegment(self: *Zld) !void {
// Set stubs and stub_helper sizes
const stubs = &seg.sections.items[self.stubs_section_index.?];
const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];
- stubs.size += nexterns * stubs.reserved2;
+ stubs.size += nstubs * stubs.reserved2;
const stub_size: u4 = switch (self.arch.?) {
.x86_64 => 10,
.aarch64 => 3 * @sizeOf(u32),
else => unreachable,
};
- stub_helper.size += nexterns * stub_size;
+ stub_helper.size += nstubs * stub_size;
var sizeofcmds: u64 = 0;
for (self.load_commands.items) |lc| {
@@ -877,7 +877,10 @@ fn allocateTextSegment(self: *Zld) !void {
fn allocateDataConstSegment(self: *Zld) !void {
const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
- const nonlazy = @intCast(u32, self.nonlazy_imports.items().len);
+ // TODO This should be worked out by scanning the relocations in the __text sections of all
+ // combined object files. For the time being, assume all externs are GOT entries (this is wasting space but
+ // should correspond to the worst-case upper bound).
+ const nexterns = @intCast(u32, self.externs.count());
const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
@@ -888,14 +891,17 @@ fn allocateDataConstSegment(self: *Zld) !void {
// TODO this will require scanning the relocations at least one to work out
// the exact amount of local GOT indirections. For the time being, set some
// default value.
- got.size += (max_local_got_indirections + nonlazy) * @sizeOf(u64);
+ got.size += (max_local_got_indirections + nexterns) * @sizeOf(u64);
try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
}
fn allocateDataSegment(self: *Zld) !void {
const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
- const lazy = @intCast(u32, self.lazy_imports.items().len);
+ // TODO This should be worked out by scanning the relocations in the __text sections of all combined
+ // object files. For the time being, assume all externs are stubs (this is wasting space but should
+ // correspond to the worst-case upper bound).
+ const nstubs = @intCast(u32, self.externs.count());
const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
@@ -904,8 +910,8 @@ fn allocateDataSegment(self: *Zld) !void {
// Set la_symbol_ptr and data size
const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?];
const data = &seg.sections.items[self.data_section_index.?];
- la_symbol_ptr.size += lazy * @sizeOf(u64);
- data.size += @sizeOf(u64); // TODO when do we need more?
+ la_symbol_ptr.size += nstubs * @sizeOf(u64);
+ data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder
try self.allocateSegment(self.data_segment_cmd_index.?, 0);
}
@@ -1303,7 +1309,13 @@ fn resolveSymbols(self: *Zld) !void {
while (self.undefs.items().len > 0) {
const entry = self.undefs.pop();
try self.externs.putNoClobber(self.allocator, entry.key, .{
- .inner = entry.value.inner,
+ .inner = .{
+ .n_strx = 0, // This will be populated once we write the string table.
+ .n_type = macho.N_UNDF | macho.N_EXT,
+ .n_sect = 0,
+ .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
+ .n_value = 0,
+ },
.file = 0,
});
}
@@ -1316,6 +1328,19 @@ fn resolveSymbols(self: *Zld) !void {
return error.UndefinedSymbolReference;
}
+
+ // Finally, put in a reference to 'dyld_stub_binder'.
+ const name = try self.allocator.dupe(u8, "dyld_stub_binder");
+ try self.externs.putNoClobber(self.allocator, name, .{
+ .inner = .{
+ .n_strx = 0, // This will be populated once we write the string table.
+ .n_type = std.macho.N_UNDF | std.macho.N_EXT,
+ .n_sect = 0,
+ .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER,
+ .n_value = 0,
+ },
+ .file = 0,
+ });
}
fn doRelocs(self: *Zld) !void {
@@ -1879,10 +1904,33 @@ fn doRelocs(self: *Zld) !void {
fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 {
const object = self.objects.items[object_id];
const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
+
+ const is_got: bool = is_got: {
+ switch (self.arch.?) {
+ .x86_64 => {
+ const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type);
+ break :is_got = switch (rel_type) {
+ .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => true,
+ else => false,
+ };
+ },
+ .aarch64 => {
+ const rel_type = @intToEnum(macho.reloc_type_aarch64, rel.r_type);
+ break :is_got = switch (rel_type) {
+ .ARM64_RELOC_GOT_LOAD_PAGE21,
+ .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
+ .ARM64_RELOC_POINTER_TO_GOT,
+ => true,
+ else => false,
+ };
+ },
+ }
+ };
+
const target_addr = blk: {
if (rel.r_extern == 1) {
const sym = object.symtab.items[rel.r_symbolnum];
- if (isLocal(&sym) or isExport(&sym)) {
+ if (sym.isSect()) {
// Relocate using section offsets only.
const target_mapping = self.mappings.get(.{
.object_id = object_id,
@@ -1894,30 +1942,13 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
const target_sect_addr = target_sect.addr + target_mapping.offset;
log.debug(" | symbol local to object", .{});
break :blk target_sect_addr + sym.n_value - source_sect.addr;
- } else if (isImport(&sym)) {
- // Relocate to either the artifact's local symbol, or an import from
+ } else if (sym.isUndf()) {
+ // Relocate to either the global symbol, or an import from
// shared library.
const sym_name = object.getString(sym.n_strx);
- if (self.locals.get(sym_name)) |locs| {
- var n_value: ?u64 = null;
- for (locs.items) |loc| {
- switch (loc.tt) {
- .Global => {
- n_value = loc.inner.n_value;
- break;
- },
- .WeakGlobal => {
- n_value = loc.inner.n_value;
- },
- .Local => {},
- }
- }
- if (n_value) |v| {
- break :blk v;
- }
- log.err("local symbol export '{s}' not found", .{sym_name});
- return error.LocalSymbolExportNotFound;
- } else if (self.lazy_imports.get(sym_name)) |ext| {
+ if (self.globals.get(sym_name)) |glob| {
+ break :blk glob.inner.n_value;
+ } else if (self.externs.getEntry(sym_name)) |ext| {
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 + ext.index * stubs.reserved2;
@@ -1928,7 +1959,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
} else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
const tlv = segment.sections.items[self.tlv_section_index.?];
- break :blk tlv.addr + self.tlv_bootstrap.?.index * @sizeOf(u64);
+ break :blk tlv.addr;
} else {
log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
return error.FailedToResolveRelocationTarget;
@@ -1951,6 +1982,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
break :blk target_sect.addr + target_mapping.offset;
}
};
+
return target_addr;
}