Commit 3bfde76cff

Jakub Konka <kubkon@jakubkonka.com>
2021-07-21 15:46:55
macho: fix text block management
For the time being, until we rewrite how atoms are handled across linkers, store two tables in the MachO linker: one for TextBlocks directly created and managed by the linker, and one for TextBlocks that were spawned by Module.Decl. This allows for correct memory clean up after linking is done.
1 parent 5276ce8
Changed files (2)
src
src/link/MachO/Object.zig
@@ -723,12 +723,13 @@ pub fn parseTextBlocks(self: *Object, macho_file: *MachO) !void {
                 break :blk block_local_sym_index;
             };
 
-            const block = try macho_file.managed_blocks.addOne(macho_file.base.allocator);
+            const block = try macho_file.base.allocator.create(TextBlock);
             block.* = TextBlock.empty;
             block.local_sym_index = block_local_sym_index;
             block.code = try self.allocator.dupe(u8, code);
             block.size = sect.size;
             block.alignment = sect.@"align";
+            try macho_file.managed_blocks.append(macho_file.base.allocator, block);
 
             try block.parseRelocsFromObject(self.allocator, relocs, self, .{
                 .base_addr = 0,
src/link/MachO.zig
@@ -188,9 +188,21 @@ text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{},
 /// Pointer to the last allocated text block
 last_text_block: ?*TextBlock = null,
 
-managed_blocks: std.ArrayListUnmanaged(TextBlock) = .{},
+/// List of TextBlocks that are owned directly by the linker.
+/// Currently these are only TextBlocks that are the result of linking
+/// object files. TextBlock which take part in incremental linking are 
+/// at present owned by Module.Decl.
+/// TODO consolidate this.
+managed_blocks: std.ArrayListUnmanaged(*TextBlock) = .{},
+
 blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
 
+/// List of Decls that are currently alive.
+/// We store them here so that we can properly dispose of any allocated
+/// memory within the TextBlock in the incremental linker.
+/// TODO consolidate this.
+decls: std.ArrayListUnmanaged(*Module.Decl) = .{},
+
 /// A list of all PIE fixups required for this run of the linker.
 /// Warning, this is currently NOT thread-safe. See the TODO below.
 /// TODO Move this list inside `updateDecl` where it should be allocated
@@ -203,7 +215,7 @@ pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},
 const StringIndexContext = struct {
     strtab: *std.ArrayListUnmanaged(u8),
 
-    pub fn eql(self: StringIndexContext, a: u32, b: u32) bool {
+    pub fn eql(_: StringIndexContext, a: u32, b: u32) bool {
         return a == b;
     }
 
@@ -2224,7 +2236,6 @@ fn resolveSymbols(self: *MachO) !void {
     for (self.tentatives.items) |sym| {
         if (symbolIsNull(sym)) continue;
 
-        const sym_name = self.getString(sym.n_strx);
         const match: MatchingSection = blk: {
             if (self.common_section_index == null) {
                 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
@@ -2263,12 +2274,13 @@ fn resolveSymbols(self: *MachO) !void {
             .local_sym_index = local_sym_index,
         };
 
-        const block = try self.managed_blocks.addOne(self.base.allocator);
+        const block = try self.base.allocator.create(TextBlock);
         block.* = TextBlock.empty;
         block.local_sym_index = local_sym_index;
         block.code = code;
         block.size = size;
         block.alignment = alignment;
+        try self.managed_blocks.append(self.base.allocator, block);
 
         // Update target section's metadata
         // TODO should we update segment's size here too?
@@ -2403,12 +2415,13 @@ fn resolveSymbols(self: *MachO) !void {
         // We create an empty atom for this symbol.
         // TODO perhaps we should special-case special symbols? Create a separate
         // linked list of atoms?
-        const block = try self.managed_blocks.addOne(self.base.allocator);
+        const block = try self.base.allocator.create(TextBlock);
         block.* = TextBlock.empty;
         block.local_sym_index = local_sym_index;
         block.code = try self.base.allocator.alloc(u8, 0);
         block.size = 0;
         block.alignment = 0;
+        try self.managed_blocks.append(self.base.allocator, block);
 
         if (self.blocks.getPtr(match)) |last| {
             last.*.next = block;
@@ -3306,12 +3319,18 @@ pub fn deinit(self: *MachO) void {
     }
     self.load_commands.deinit(self.base.allocator);
 
-    for (self.managed_blocks.items) |*block| {
+    for (self.managed_blocks.items) |block| {
         block.deinit(self.base.allocator);
+        self.base.allocator.destroy(block);
     }
     self.managed_blocks.deinit(self.base.allocator);
     self.blocks.deinit(self.base.allocator);
     self.text_block_free_list.deinit(self.base.allocator);
+
+    for (self.decls.items) |decl| {
+        decl.link.macho.deinit(self.base.allocator);
+    }
+    self.decls.deinit(self.base.allocator);
 }
 
 pub fn closeFiles(self: MachO) void {
@@ -3325,7 +3344,7 @@ pub fn closeFiles(self: MachO) void {
 
 fn freeTextBlock(self: *MachO, text_block: *TextBlock) void {
     log.debug("freeTextBlock {*}", .{text_block});
-    // text_block.deinit(self.base.allocator);
+    text_block.deinit(self.base.allocator);
 
     var already_have_free_list_node = false;
     {
@@ -3412,6 +3431,9 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
 
     try self.locals.ensureUnusedCapacity(self.base.allocator, 1);
     try self.got_entries.ensureUnusedCapacity(self.base.allocator, 1);
+    try self.decls.ensureUnusedCapacity(self.base.allocator, 1);
+
+    self.decls.appendAssumeCapacity(decl);
 
     if (self.locals_free_list.popOrNull()) |i| {
         log.debug("reusing symbol index {d} for {s}", .{ i, decl.name });
@@ -3497,7 +3519,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
             .externally_managed => |x| break :blk x,
             .appended => {
                 decl.link.macho.code = code_buffer.toOwnedSlice();
-                log.warn("WAT", .{});
                 break :blk decl.link.macho.code;
             },
             .fail => |em| {