Commit e17f12dd64

Jakub Konka <kubkon@jakubkonka.com>
2021-07-12 23:56:36
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.
1 parent de30a70
Changed files (3)
src/link/MachO/Object.zig
@@ -431,30 +431,27 @@ 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);
-            for (aliases.items) |alias| {
-                out.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;
 
+        if (aliases.items.len > 0) {
+            try block.aliases.ensureTotalCapacity(aliases.items.len);
+            for (aliases.items) |alias| {
+                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;
+            }
+        }
+
         const relocs = filterRelocs(self.relocs, start_addr, end_addr);
         if (relocs.len > 0) {
             try self.object.parseRelocs(self.zld, relocs, block, start_addr);
@@ -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;
 
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 = .{
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;