Commit 87602092fa

Jakub Konka <kubkon@jakubkonka.com>
2023-10-02 17:16:27
elf: write .got in bulk after scanning objects
1 parent d565f8b
Changed files (1)
src
link
src/link/Elf.zig
@@ -111,7 +111,7 @@ symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
 
 phdr_table_dirty: bool = false,
 shdr_table_dirty: bool = false,
-got_dirty: bool = false,
+got_addresses_dirty: bool = false,
 
 debug_strtab_dirty: bool = false,
 debug_abbrev_section_dirty: bool = false,
@@ -942,7 +942,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
         // and grow.
         {
             const dirty_addr = phdr.p_vaddr + phdr.p_memsz;
-            self.got_dirty = for (self.got.entries.items) |entry| {
+            self.got_addresses_dirty = for (self.got.entries.items) |entry| {
                 if (self.symbol(entry.symbol_index).value >= dirty_addr) break true;
             } else false;
 
@@ -1333,15 +1333,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
     }
     try self.writeObjects();
 
-    if (self.got_dirty) {
-        const shdr = &self.shdrs.items[self.got_section_index.?];
-        var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self));
-        defer buffer.deinit();
-        try self.got.writeAllEntries(self, buffer.writer());
-        try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
-        self.got_dirty = false;
-    }
-
     // Look for entry address in objects if not set by the incremental compiler.
     if (self.entry_addr == null) {
         const entry: ?[]const u8 = entry: {
@@ -1541,6 +1532,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
     assert(!self.shdr_table_dirty);
     assert(!self.debug_strtab_dirty);
     assert(!self.got.dirty);
+    assert(!self.got_addresses_dirty);
 }
 
 const ParseError = error{
@@ -1789,8 +1781,7 @@ fn scanRelocs(self: *Elf) !void {
         if (sym.flags.needs_got) {
             log.debug("'{s}' needs GOT", .{sym.name(self)});
             // TODO how can we tell we need to write it again, aka the entry is dirty?
-            const gop = try sym.getOrCreateGotEntry(@intCast(sym_index), self);
-            try self.got.writeEntry(self, gop.index);
+            _ = try sym.getOrCreateGotEntry(@intCast(sym_index), self);
         }
     }
 }
@@ -3472,6 +3463,15 @@ fn initSyntheticSections(self: *Elf) !void {
         .p64 => false,
     };
 
+    if (self.got.entries.items.len > 0 and self.got_section_index == null) {
+        self.got_section_index = try self.addSection(.{
+            .name = ".got",
+            .type = elf.SHT_PROGBITS,
+            .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
+            .addralign = self.ptrWidthBytes(),
+        });
+    }
+
     if (self.symtab_section_index == null) {
         self.symtab_section_index = try self.addSection(.{
             .name = ".symtab",
@@ -3499,9 +3499,18 @@ fn initSyntheticSections(self: *Elf) !void {
 }
 
 fn updateSyntheticSectionSizes(self: *Elf) !void {
+    if (self.got_section_index) |index| {
+        if (self.got.dirty) {
+            try self.growAllocSection(index, self.got.size(self));
+            self.got.dirty = false;
+            self.got_addresses_dirty = true;
+        }
+    }
+
     if (self.symtab_section_index != null) {
         try self.updateSymtabSize();
     }
+
     if (self.strtab_section_index) |index| {
         // TODO I don't really this here but we need it to add symbol names from GOT and other synthetic
         // sections into .strtab for easier debugging.
@@ -3510,6 +3519,7 @@ fn updateSyntheticSectionSizes(self: *Elf) !void {
         }
         try self.growNonAllocSection(index, self.strtab.buffer.items.len, 1, false);
     }
+
     if (self.shstrtab_section_index) |index| {
         try self.growNonAllocSection(index, self.shstrtab.buffer.items.len, 1, false);
     }
@@ -3560,14 +3570,25 @@ fn updateSymtabSize(self: *Elf) !void {
 }
 
 fn writeSyntheticSections(self: *Elf) !void {
+    if (self.got_addresses_dirty) {
+        const shdr = &self.shdrs.items[self.got_section_index.?];
+        var buffer = try std.ArrayList(u8).initCapacity(self.base.allocator, self.got.size(self));
+        defer buffer.deinit();
+        try self.got.writeAllEntries(self, buffer.writer());
+        try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
+        self.got_addresses_dirty = false;
+    }
+
     if (self.shstrtab_section_index) |index| {
         const shdr = self.shdrs.items[index];
         try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset);
     }
+
     if (self.strtab_section_index) |index| {
         const shdr = self.shdrs.items[index];
         try self.base.file.?.pwriteAll(self.strtab.buffer.items, shdr.sh_offset);
     }
+
     if (self.symtab_section_index) |_| {
         try self.writeSymtab();
     }