Commit 37e2958f81

Jakub Konka <kubkon@jakubkonka.com>
2023-09-06 23:20:49
elf: write symbtab
1 parent a2b5a46
Changed files (1)
src
link
src/link/Elf.zig
@@ -1003,7 +1003,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
 
     const target_endian = self.base.options.target.cpu.arch.endian();
     const foreign_endian = target_endian != builtin.cpu.arch.endian();
-    _ = foreign_endian;
 
     if (self.dwarf) |*dw| {
         try dw.flushModule(module);
@@ -1044,212 +1043,212 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
         }
     }
 
-    // try self.writeSymbols();
+    try self.writeSymbols();
 
     if (build_options.enable_logging) {
         state_log.debug("{}", .{self.dumpState()});
     }
 
-    // if (self.dwarf) |*dw| {
-    //     if (self.debug_abbrev_section_dirty) {
-    //         try dw.writeDbgAbbrev();
-    //         if (!self.shdr_table_dirty) {
-    //             // Then it won't get written with the others and we need to do it.
-    //             try self.writeSectHeader(self.debug_abbrev_section_index.?);
-    //         }
-    //         self.debug_abbrev_section_dirty = false;
-    //     }
-
-    //     if (self.debug_info_header_dirty) {
-    //         // Currently only one compilation unit is supported, so the address range is simply
-    //         // identical to the main program header virtual address and memory size.
-    //         const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
-    //         const low_pc = text_phdr.p_vaddr;
-    //         const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
-    //         try dw.writeDbgInfoHeader(module, low_pc, high_pc);
-    //         self.debug_info_header_dirty = false;
-    //     }
-
-    //     if (self.debug_aranges_section_dirty) {
-    //         // Currently only one compilation unit is supported, so the address range is simply
-    //         // identical to the main program header virtual address and memory size.
-    //         const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
-    //         try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
-    //         if (!self.shdr_table_dirty) {
-    //             // Then it won't get written with the others and we need to do it.
-    //             try self.writeSectHeader(self.debug_aranges_section_index.?);
-    //         }
-    //         self.debug_aranges_section_dirty = false;
-    //     }
-
-    //     if (self.debug_line_header_dirty) {
-    //         try dw.writeDbgLineHeader();
-    //         self.debug_line_header_dirty = false;
-    //     }
-    // }
-
-    // if (self.phdr_table_dirty) {
-    //     const phsize: u64 = switch (self.ptr_width) {
-    //         .p32 => @sizeOf(elf.Elf32_Phdr),
-    //         .p64 => @sizeOf(elf.Elf64_Phdr),
-    //     };
-
-    //     const phdr_table_index = self.phdr_table_index.?;
-    //     const phdr_table = &self.program_headers.items[phdr_table_index];
-    //     const phdr_table_load = &self.program_headers.items[self.phdr_table_load_index.?];
-
-    //     const allocated_size = self.allocatedSize(phdr_table.p_offset);
-    //     const needed_size = self.program_headers.items.len * phsize;
-
-    //     if (needed_size > allocated_size) {
-    //         phdr_table.p_offset = 0; // free the space
-    //         phdr_table.p_offset = self.findFreeSpace(needed_size, @as(u32, @intCast(phdr_table.p_align)));
-    //     }
-
-    //     phdr_table_load.p_offset = mem.alignBackward(u64, phdr_table.p_offset, phdr_table_load.p_align);
-    //     const load_align_offset = phdr_table.p_offset - phdr_table_load.p_offset;
-    //     phdr_table_load.p_filesz = load_align_offset + needed_size;
-    //     phdr_table_load.p_memsz = load_align_offset + needed_size;
-
-    //     phdr_table.p_filesz = needed_size;
-    //     phdr_table.p_vaddr = phdr_table_load.p_vaddr + load_align_offset;
-    //     phdr_table.p_paddr = phdr_table_load.p_paddr + load_align_offset;
-    //     phdr_table.p_memsz = needed_size;
-
-    //     switch (self.ptr_width) {
-    //         .p32 => {
-    //             const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
-    //             defer gpa.free(buf);
-
-    //             for (buf, 0..) |*phdr, i| {
-    //                 phdr.* = progHeaderTo32(self.program_headers.items[i]);
-    //                 if (foreign_endian) {
-    //                     mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
-    //                 }
-    //             }
-    //             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
-    //         },
-    //         .p64 => {
-    //             const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
-    //             defer gpa.free(buf);
-
-    //             for (buf, 0..) |*phdr, i| {
-    //                 phdr.* = self.program_headers.items[i];
-    //                 if (foreign_endian) {
-    //                     mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
-    //                 }
-    //             }
-    //             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
-    //         },
-    //     }
-
-    //     // We don't actually care if the phdr load section overlaps, only the phdr section matters.
-    //     phdr_table_load.p_offset = 0;
-    //     phdr_table_load.p_filesz = 0;
-
-    //     self.phdr_table_dirty = false;
-    // }
-
-    // {
-    //     const shdr_index = self.shstrtab_section_index.?;
-    //     if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
-    //         try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
-    //         const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
-    //         try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
-    //         self.shstrtab_dirty = false;
-    //     }
-    // }
-
-    // {
-    //     const shdr_index = self.strtab_section_index.?;
-    //     if (self.strtab_dirty or self.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
-    //         try self.growNonAllocSection(shdr_index, self.strtab.buffer.items.len, 1, false);
-    //         const strtab_sect = self.sections.items(.shdr)[shdr_index];
-    //         try self.base.file.?.pwriteAll(self.strtab.buffer.items, strtab_sect.sh_offset);
-    //         self.strtab_dirty = false;
-    //     }
-    // }
-
-    // if (self.dwarf) |dwarf| {
-    //     const shdr_index = self.debug_str_section_index.?;
-    //     if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
-    //         try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false);
-    //         const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
-    //         try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset);
-    //         self.debug_strtab_dirty = false;
-    //     }
-    // }
-
-    // if (self.shdr_table_dirty) {
-    //     const shsize: u64 = switch (self.ptr_width) {
-    //         .p32 => @sizeOf(elf.Elf32_Shdr),
-    //         .p64 => @sizeOf(elf.Elf64_Shdr),
-    //     };
-    //     const shalign: u16 = switch (self.ptr_width) {
-    //         .p32 => @alignOf(elf.Elf32_Shdr),
-    //         .p64 => @alignOf(elf.Elf64_Shdr),
-    //     };
-    //     const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
-    //     const needed_size = self.sections.slice().len * shsize;
-
-    //     if (needed_size > allocated_size) {
-    //         self.shdr_table_offset = null; // free the space
-    //         self.shdr_table_offset = self.findFreeSpace(needed_size, shalign);
-    //     }
-
-    //     switch (self.ptr_width) {
-    //         .p32 => {
-    //             const slice = self.sections.slice();
-    //             const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
-    //             defer gpa.free(buf);
-
-    //             for (buf, 0..) |*shdr, i| {
-    //                 shdr.* = sectHeaderTo32(slice.items(.shdr)[i]);
-    //                 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
-    //                 if (foreign_endian) {
-    //                     mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
-    //                 }
-    //             }
-    //             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
-    //         },
-    //         .p64 => {
-    //             const slice = self.sections.slice();
-    //             const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
-    //             defer gpa.free(buf);
-
-    //             for (buf, 0..) |*shdr, i| {
-    //                 shdr.* = slice.items(.shdr)[i];
-    //                 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
-    //                 if (foreign_endian) {
-    //                     mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
-    //                 }
-    //             }
-    //             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
-    //         },
-    //     }
-    //     self.shdr_table_dirty = false;
-    // }
-    // if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {
-    //     log.debug("flushing. no_entry_point_found = true", .{});
-    //     self.error_flags.no_entry_point_found = true;
-    // } else {
-    //     log.debug("flushing. no_entry_point_found = false", .{});
-    //     self.error_flags.no_entry_point_found = false;
-    //     try self.writeElfHeader();
-    // }
-
-    // // The point of flush() is to commit changes, so in theory, nothing should
-    // // be dirty after this. However, it is possible for some things to remain
-    // // dirty because they fail to be written in the event of compile errors,
-    // // such as debug_line_header_dirty and debug_info_header_dirty.
-    // assert(!self.debug_abbrev_section_dirty);
-    // assert(!self.debug_aranges_section_dirty);
-    // assert(!self.phdr_table_dirty);
-    // assert(!self.shdr_table_dirty);
-    // assert(!self.shstrtab_dirty);
-    // assert(!self.strtab_dirty);
-    // assert(!self.debug_strtab_dirty);
-    // assert(!self.got_table_count_dirty);
+    if (self.dwarf) |*dw| {
+        if (self.debug_abbrev_section_dirty) {
+            try dw.writeDbgAbbrev();
+            if (!self.shdr_table_dirty) {
+                // Then it won't get written with the others and we need to do it.
+                try self.writeSectHeader(self.debug_abbrev_section_index.?);
+            }
+            self.debug_abbrev_section_dirty = false;
+        }
+
+        if (self.debug_info_header_dirty) {
+            // Currently only one compilation unit is supported, so the address range is simply
+            // identical to the main program header virtual address and memory size.
+            const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
+            const low_pc = text_phdr.p_vaddr;
+            const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
+            try dw.writeDbgInfoHeader(module, low_pc, high_pc);
+            self.debug_info_header_dirty = false;
+        }
+
+        if (self.debug_aranges_section_dirty) {
+            // Currently only one compilation unit is supported, so the address range is simply
+            // identical to the main program header virtual address and memory size.
+            const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
+            try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
+            if (!self.shdr_table_dirty) {
+                // Then it won't get written with the others and we need to do it.
+                try self.writeSectHeader(self.debug_aranges_section_index.?);
+            }
+            self.debug_aranges_section_dirty = false;
+        }
+
+        if (self.debug_line_header_dirty) {
+            try dw.writeDbgLineHeader();
+            self.debug_line_header_dirty = false;
+        }
+    }
+
+    if (self.phdr_table_dirty) {
+        const phsize: u64 = switch (self.ptr_width) {
+            .p32 => @sizeOf(elf.Elf32_Phdr),
+            .p64 => @sizeOf(elf.Elf64_Phdr),
+        };
+
+        const phdr_table_index = self.phdr_table_index.?;
+        const phdr_table = &self.program_headers.items[phdr_table_index];
+        const phdr_table_load = &self.program_headers.items[self.phdr_table_load_index.?];
+
+        const allocated_size = self.allocatedSize(phdr_table.p_offset);
+        const needed_size = self.program_headers.items.len * phsize;
+
+        if (needed_size > allocated_size) {
+            phdr_table.p_offset = 0; // free the space
+            phdr_table.p_offset = self.findFreeSpace(needed_size, @as(u32, @intCast(phdr_table.p_align)));
+        }
+
+        phdr_table_load.p_offset = mem.alignBackward(u64, phdr_table.p_offset, phdr_table_load.p_align);
+        const load_align_offset = phdr_table.p_offset - phdr_table_load.p_offset;
+        phdr_table_load.p_filesz = load_align_offset + needed_size;
+        phdr_table_load.p_memsz = load_align_offset + needed_size;
+
+        phdr_table.p_filesz = needed_size;
+        phdr_table.p_vaddr = phdr_table_load.p_vaddr + load_align_offset;
+        phdr_table.p_paddr = phdr_table_load.p_paddr + load_align_offset;
+        phdr_table.p_memsz = needed_size;
+
+        switch (self.ptr_width) {
+            .p32 => {
+                const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
+                defer gpa.free(buf);
+
+                for (buf, 0..) |*phdr, i| {
+                    phdr.* = progHeaderTo32(self.program_headers.items[i]);
+                    if (foreign_endian) {
+                        mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
+                    }
+                }
+                try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
+            },
+            .p64 => {
+                const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
+                defer gpa.free(buf);
+
+                for (buf, 0..) |*phdr, i| {
+                    phdr.* = self.program_headers.items[i];
+                    if (foreign_endian) {
+                        mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
+                    }
+                }
+                try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
+            },
+        }
+
+        // We don't actually care if the phdr load section overlaps, only the phdr section matters.
+        phdr_table_load.p_offset = 0;
+        phdr_table_load.p_filesz = 0;
+
+        self.phdr_table_dirty = false;
+    }
+
+    {
+        const shdr_index = self.shstrtab_section_index.?;
+        if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
+            try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
+            const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
+            try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
+            self.shstrtab_dirty = false;
+        }
+    }
+
+    {
+        const shdr_index = self.strtab_section_index.?;
+        if (self.strtab_dirty or self.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
+            try self.growNonAllocSection(shdr_index, self.strtab.buffer.items.len, 1, false);
+            const strtab_sect = self.sections.items(.shdr)[shdr_index];
+            try self.base.file.?.pwriteAll(self.strtab.buffer.items, strtab_sect.sh_offset);
+            self.strtab_dirty = false;
+        }
+    }
+
+    if (self.dwarf) |dwarf| {
+        const shdr_index = self.debug_str_section_index.?;
+        if (self.debug_strtab_dirty or dwarf.strtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
+            try self.growNonAllocSection(shdr_index, dwarf.strtab.buffer.items.len, 1, false);
+            const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
+            try self.base.file.?.pwriteAll(dwarf.strtab.buffer.items, debug_strtab_sect.sh_offset);
+            self.debug_strtab_dirty = false;
+        }
+    }
+
+    if (self.shdr_table_dirty) {
+        const shsize: u64 = switch (self.ptr_width) {
+            .p32 => @sizeOf(elf.Elf32_Shdr),
+            .p64 => @sizeOf(elf.Elf64_Shdr),
+        };
+        const shalign: u16 = switch (self.ptr_width) {
+            .p32 => @alignOf(elf.Elf32_Shdr),
+            .p64 => @alignOf(elf.Elf64_Shdr),
+        };
+        const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
+        const needed_size = self.sections.slice().len * shsize;
+
+        if (needed_size > allocated_size) {
+            self.shdr_table_offset = null; // free the space
+            self.shdr_table_offset = self.findFreeSpace(needed_size, shalign);
+        }
+
+        switch (self.ptr_width) {
+            .p32 => {
+                const slice = self.sections.slice();
+                const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
+                defer gpa.free(buf);
+
+                for (buf, 0..) |*shdr, i| {
+                    shdr.* = sectHeaderTo32(slice.items(.shdr)[i]);
+                    log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
+                    if (foreign_endian) {
+                        mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
+                    }
+                }
+                try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
+            },
+            .p64 => {
+                const slice = self.sections.slice();
+                const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
+                defer gpa.free(buf);
+
+                for (buf, 0..) |*shdr, i| {
+                    shdr.* = slice.items(.shdr)[i];
+                    log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
+                    if (foreign_endian) {
+                        mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
+                    }
+                }
+                try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
+            },
+        }
+        self.shdr_table_dirty = false;
+    }
+    if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {
+        log.debug("flushing. no_entry_point_found = true", .{});
+        self.error_flags.no_entry_point_found = true;
+    } else {
+        log.debug("flushing. no_entry_point_found = false", .{});
+        self.error_flags.no_entry_point_found = false;
+        try self.writeElfHeader();
+    }
+
+    // The point of flush() is to commit changes, so in theory, nothing should
+    // be dirty after this. However, it is possible for some things to remain
+    // dirty because they fail to be written in the event of compile errors,
+    // such as debug_line_header_dirty and debug_info_header_dirty.
+    assert(!self.debug_abbrev_section_dirty);
+    assert(!self.debug_aranges_section_dirty);
+    assert(!self.phdr_table_dirty);
+    assert(!self.shdr_table_dirty);
+    assert(!self.shstrtab_dirty);
+    assert(!self.strtab_dirty);
+    assert(!self.debug_strtab_dirty);
+    assert(!self.got_table_count_dirty);
 }
 
 fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
@@ -2795,12 +2794,13 @@ fn writeSymbols(self: *Elf) !void {
         .p32 => @alignOf(elf.Elf32_Sym),
         .p64 => @alignOf(elf.Elf64_Sym),
     };
+    const zig_module = self.file(self.zig_module_index.?).?.zig_module;
 
     const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
-    shdr.sh_info = @intCast(self.locals.items.len);
+    shdr.sh_info = @intCast(zig_module.locals().len);
     self.markDirty(self.symtab_section_index.?, null);
 
-    const nsyms = self.locals.items.len + self.globals.items.len;
+    const nsyms = zig_module.locals().len + zig_module.globals().len;
     const needed_size = nsyms * sym_size;
     try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
 
@@ -2811,15 +2811,17 @@ fn writeSymbols(self: *Elf) !void {
             const buf = try gpa.alloc(elf.Elf32_Sym, nsyms);
             defer gpa.free(buf);
 
-            for (buf[0..self.locals.items.len], self.locals.items) |*sym, local| {
-                elf32SymFromSym(local, sym);
+            for (buf[0..zig_module.locals().len], zig_module.locals()) |*sym, local_index| {
+                const local = self.symbol(local_index);
+                elf32SymFromSym(local.sourceSymbol(self).*, sym);
                 if (foreign_endian) {
                     mem.byteSwapAllFields(elf.Elf32_Sym, sym);
                 }
             }
 
-            for (buf[self.locals.items.len..], self.globals.items) |*sym, glob| {
-                elf32SymFromSym(self.symbol(glob).*, sym);
+            for (buf[zig_module.locals().len..], zig_module.globals()) |*sym, global_index| {
+                const global = self.symbol(global_index);
+                elf32SymFromSym(global.sourceSymbol(self).*, sym);
                 if (foreign_endian) {
                     mem.byteSwapAllFields(elf.Elf32_Sym, sym);
                 }
@@ -2829,15 +2831,17 @@ fn writeSymbols(self: *Elf) !void {
         .p64 => {
             const buf = try gpa.alloc(elf.Elf64_Sym, nsyms);
             defer gpa.free(buf);
-            for (buf[0..self.locals.items.len], self.locals.items) |*sym, local| {
-                sym.* = local;
+            for (buf[0..zig_module.locals().len], zig_module.locals()) |*sym, local_index| {
+                const local = self.symbol(local_index);
+                sym.* = local.sourceSymbol(self).*;
                 if (foreign_endian) {
                     mem.byteSwapAllFields(elf.Elf64_Sym, sym);
                 }
             }
 
-            for (buf[self.locals.items.len..], self.globals.items) |*sym, glob| {
-                sym.* = self.symbol(glob).*;
+            for (buf[zig_module.locals().len..], zig_module.globals()) |*sym, global_index| {
+                const global = self.symbol(global_index);
+                sym.* = global.sourceSymbol(self).*;
                 if (foreign_endian) {
                     mem.byteSwapAllFields(elf.Elf64_Sym, sym);
                 }