From e17f12dd643e9edd90abb66b183d2a59eddc248c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 12 Jul 2021 23:56:36 +0200 Subject: [PATCH] zld: fix incorrectly worked out section size Also, add a solution to a degenerate case where on x86_64 a relocation refers to a cell in a section via section start address even though a symbol exists. In such case, make the section spawned symbol an alias of the actual symbol. --- src/link/MachO/Object.zig | 48 +++++++++++++++++++++++---------------- src/link/MachO/Zld.zig | 23 ++++++++----------- src/link/MachO/reloc.zig | 4 ++-- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index abd5a39a69..b53a31af56 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -431,29 +431,26 @@ const TextBlockParser = struct { else max_align; - const alias_only_indices = if (aliases.items.len > 0) blk: { - var out = std.ArrayList(u32).init(self.allocator); - try out.ensureTotalCapacity(aliases.items.len); + const block = try self.allocator.create(TextBlock); + errdefer self.allocator.destroy(block); + + block.* = TextBlock.init(self.allocator); + block.local_sym_index = senior_nlist.index; + block.code = try self.allocator.dupe(u8, code); + block.size = size; + block.alignment = actual_align; + + if (aliases.items.len > 0) { + try block.aliases.ensureTotalCapacity(aliases.items.len); for (aliases.items) |alias| { - out.appendAssumeCapacity(alias.index); + block.aliases.appendAssumeCapacity(alias.index); const sym = self.zld.locals.items[alias.index]; const reg = &sym.payload.regular; reg.segment_id = self.match.seg; reg.section_id = self.match.sect; } - break :blk out.toOwnedSlice(); - } else null; - - const block = try self.allocator.create(TextBlock); - errdefer self.allocator.destroy(block); - - block.* = TextBlock.init(self.allocator); - block.local_sym_index = senior_nlist.index; - block.aliases = alias_only_indices; - block.code = try self.allocator.dupe(u8, code); - block.size = size; - block.alignment = actual_align; + } const relocs = filterRelocs(self.relocs, start_addr, end_addr); if (relocs.len > 0) { @@ -617,7 +614,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { const tsect = &tseg.sections.items[match.sect]; const new_alignment = math.max(tsect.@"align", block.alignment); const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); - const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2); + const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; tsect.size = new_size; tsect.@"align" = new_alignment; @@ -653,6 +650,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { } } + if (reg.address == sect.addr) { + if (self.sections_as_symbols.get(sect_id)) |alias| { + // Add alias. + const local_sym_index = @intCast(u32, zld.locals.items.len); + const reg_alias = &alias.payload.regular; + reg_alias.segment_id = match.seg; + reg_alias.section_id = match.sect; + reg_alias.local_sym_index = local_sym_index; + try block.aliases.append(local_sym_index); + try zld.locals.append(zld.allocator, alias); + } + } + // Update target section's metadata // TODO should we update segment's size here too? // How does it tie with incremental space allocs? @@ -660,7 +670,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { const tsect = &tseg.sections.items[match.sect]; const new_alignment = math.max(tsect.@"align", block.alignment); const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); - const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2); + const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; tsect.size = new_size; tsect.@"align" = new_alignment; @@ -764,7 +774,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { const tsect = &tseg.sections.items[match.sect]; const new_alignment = math.max(tsect.@"align", block.alignment); const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); - const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2); + const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; tsect.size = new_size; tsect.@"align" = new_alignment; diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 995269440f..40ab52f062 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -125,7 +125,7 @@ pub const Output = struct { pub const TextBlock = struct { allocator: *Allocator, local_sym_index: u32, - aliases: ?[]u32 = null, + aliases: std.ArrayList(u32), references: std.AutoArrayHashMap(u32, void), contained: ?[]SymbolAtOffset = null, code: []u8, @@ -146,6 +146,7 @@ pub const TextBlock = struct { return .{ .allocator = allocator, .local_sym_index = undefined, + .aliases = std.ArrayList(u32).init(allocator), .references = std.AutoArrayHashMap(u32, void).init(allocator), .code = undefined, .relocs = std.ArrayList(Relocation).init(allocator), @@ -157,9 +158,7 @@ pub const TextBlock = struct { } pub fn deinit(self: *TextBlock) void { - if (self.aliases) |aliases| { - self.allocator.free(aliases); - } + self.aliases.deinit(); self.references.deinit(); if (self.contained) |contained| { self.allocator.free(contained); @@ -179,9 +178,9 @@ pub const TextBlock = struct { pub fn print_this(self: *const TextBlock, zld: *Zld) void { log.warn("TextBlock", .{}); log.warn(" {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] }); - if (self.aliases) |aliases| { + if (self.aliases.items.len > 0) { log.warn(" aliases:", .{}); - for (aliases) |index| { + for (self.aliases.items) |index| { log.warn(" {}: {}", .{ index, zld.locals.items[index] }); } } @@ -1082,12 +1081,10 @@ fn allocateTextBlocks(self: *Zld) !void { }); // Update each alias (if any) - if (block.aliases) |aliases| { - for (aliases) |index| { - const alias_sym = self.locals.items[index]; - assert(alias_sym.payload == .regular); - alias_sym.payload.regular.address = base_addr; - } + for (block.aliases.items) |index| { + const alias_sym = self.locals.items[index]; + assert(alias_sym.payload == .regular); + alias_sym.payload.regular.address = base_addr; } // Update each symbol contained within the TextBlock @@ -1623,7 +1620,7 @@ fn resolveSymbols(self: *Zld) !void { const tsect = &tseg.sections.items[match.sect]; const new_alignment = math.max(tsect.@"align", block.alignment); const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); - const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2); + const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; tsect.size = new_size; tsect.@"align" = new_alignment; diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index 2008d53e3f..d92d047cd9 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -878,9 +878,9 @@ pub const Parser = struct { if (rel.r_extern == 0) { const source_sym = self.zld.locals.items[self.block.local_sym_index].payload.regular; - const source_addr = source_sym.address + parsed.offset + @intCast(u32, addend) + 4; + const source_addr = source_sym.address + parsed.offset + 4; const target_sym = parsed.target.payload.regular; - addend = @intCast(i64, source_addr) - @intCast(i64, target_sym.address); + addend = @intCast(i64, source_addr) + addend - @intCast(i64, target_sym.address); } parsed.payload = .{