Commit 1b69b0c621

Jakub Konka <kubkon@jakubkonka.com>
2023-11-06 14:26:35
elf: clearly separate updating and writing symtab from only ZigObject
1 parent 281daba
Changed files (2)
src
src/link/Elf/file.zig
@@ -161,7 +161,7 @@ pub const File = union(enum) {
     }
 
     pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {
-        var ilocal = ctx.ilocal;
+        var ilocal: usize = ctx.ilocal;
         for (file.locals()) |local_index| {
             const local = elf_file.symbol(local_index);
             if (!local.flags.output_symtab) continue;
@@ -173,7 +173,7 @@ pub const File = union(enum) {
             ilocal += 1;
         }
 
-        var iglobal = ctx.iglobal;
+        var iglobal: usize = ctx.iglobal;
         for (file.globals()) |global_index| {
             const global = elf_file.symbol(global_index);
             const file_ptr = global.file(elf_file) orelse continue;
src/link/Elf.zig
@@ -1539,14 +1539,14 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
         try self.initShStrtab();
         try self.sortShdrs();
         zig_object.updateRelaSectionSizes(self);
-        try self.updateSymtabSize();
+        self.updateSymtabSizeObject(zig_object);
         self.updateShStrtabSize();
 
         try self.allocateNonAllocSections();
 
         try self.writeShdrTable();
         try zig_object.writeRelaSections(self);
-        try self.writeSymtab();
+        try self.writeSymtabObject(zig_object);
         try self.writeShStrtab();
         try self.writeElfHeader();
     }
@@ -4060,7 +4060,7 @@ fn updateSectionSizes(self: *Elf) !void {
         self.shdrs.items[index].sh_size = self.verneed.size();
     }
 
-    try self.updateSymtabSize();
+    self.updateSymtabSize();
     self.updateShStrtabSize();
 }
 
@@ -4483,7 +4483,7 @@ fn writeAtoms(self: *Elf) !void {
     try self.reportUndefined(&undefs);
 }
 
-fn updateSymtabSize(self: *Elf) !void {
+fn updateSymtabSize(self: *Elf) void {
     var sizes = SymtabSize{};
 
     if (self.zigObjectPtr()) |zig_object| {
@@ -4544,6 +4544,25 @@ fn updateSymtabSize(self: *Elf) !void {
     strtab.sh_size = sizes.strsize + 1;
 }
 
+fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void {
+    zig_object.asFile().updateSymtabSize(self);
+    const sizes = zig_object.output_symtab_size;
+
+    const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
+    symtab_shdr.sh_info = sizes.nlocals + 1;
+    symtab_shdr.sh_link = self.strtab_section_index.?;
+
+    const sym_size: u64 = switch (self.ptr_width) {
+        .p32 => @sizeOf(elf.Elf32_Sym),
+        .p64 => @sizeOf(elf.Elf64_Sym),
+    };
+    const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
+    symtab_shdr.sh_size = needed_size;
+
+    const strtab = &self.shdrs.items[self.strtab_section_index.?];
+    strtab.sh_size = sizes.strsize + 1;
+}
+
 fn writeSyntheticSections(self: *Elf) !void {
     const gpa = self.base.allocator;
 
@@ -4788,6 +4807,54 @@ fn writeSymtab(self: *Elf) !void {
     try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
 }
 
+fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
+    const gpa = self.base.allocator;
+    const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
+    const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
+    const sym_size: u64 = switch (self.ptr_width) {
+        .p32 => @sizeOf(elf.Elf32_Sym),
+        .p64 => @sizeOf(elf.Elf64_Sym),
+    };
+    const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
+
+    log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });
+
+    try self.symtab.resize(gpa, nsyms);
+    const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
+    try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
+
+    zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info });
+
+    const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
+    switch (self.ptr_width) {
+        .p32 => {
+            const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
+            defer gpa.free(buf);
+
+            for (buf, self.symtab.items) |*out, sym| {
+                out.* = .{
+                    .st_name = sym.st_name,
+                    .st_info = sym.st_info,
+                    .st_other = sym.st_other,
+                    .st_shndx = sym.st_shndx,
+                    .st_value = @as(u32, @intCast(sym.st_value)),
+                    .st_size = @as(u32, @intCast(sym.st_size)),
+                };
+                if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
+            }
+            try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
+        },
+        .p64 => {
+            if (foreign_endian) {
+                for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
+            }
+            try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
+        },
+    }
+
+    try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
+}
+
 /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
 fn ptrWidthBytes(self: Elf) u8 {
     return switch (self.ptr_width) {