authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-07 15:45:58+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-07 15:45:58+02:00
log9691d1a30ff524be5dc2cc88855b7887cd7f26f3
tree0c66f069bb642295eb2b830bf5cd5746c4b271fd
parent37e2958f8125b08d4acb9175bf0bd30cd9872961

elf: use zld's update mechanism for symtab for Zig module


3 files changed, 141 insertions(+), 85 deletions(-)

src/link/Elf.zig+71-61
...@@ -1043,7 +1043,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1043,7 +1043,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1043 }1043 }
1044 }1044 }
10451045
1046 try self.writeSymbols();1046 try self.updateSymtabSize();
1047 try self.writeSymtab();
10471048
1048 if (build_options.enable_logging) {1049 if (build_options.enable_logging) {
1049 state_log.debug("{}", .{self.dumpState()});1050 state_log.debug("{}", .{self.dumpState()});
...@@ -2662,14 +2663,7 @@ pub fn deleteDeclExport(...@@ -2662,14 +2663,7 @@ pub fn deleteDeclExport(
2662 assert(self.resolver.fetchSwapRemove(sym.name_offset) != null); // TODO don't delete it if it's not dominant2663 assert(self.resolver.fetchSwapRemove(sym.name_offset) != null); // TODO don't delete it if it's not dominant
2663 sym.* = .{};2664 sym.* = .{};
2664 // TODO free list for esym!2665 // TODO free list for esym!
2665 esym.* = .{2666 esym.* = null_sym;
2666 .st_name = 0,
2667 .st_info = 0,
2668 .st_other = 0,
2669 .st_shndx = 0,
2670 .st_value = 0,
2671 .st_size = 0,
2672 };
2673 self.symbols_free_list.append(gpa, sym_index.*) catch {};2667 self.symbols_free_list.append(gpa, sym_index.*) catch {};
2674 sym_index.* = 0;2668 sym_index.* = 0;
2675}2669}
...@@ -2773,19 +2767,20 @@ fn writeOffsetTableEntry(self: *Elf, index: @TypeOf(self.got_table).Index) !void...@@ -2773,19 +2767,20 @@ fn writeOffsetTableEntry(self: *Elf, index: @TypeOf(self.got_table).Index) !void
2773 }2767 }
2774}2768}
27752769
2776fn elf32SymFromSym(sym: elf.Elf64_Sym, out: *elf.Elf32_Sym) void {2770fn updateSymtabSize(self: *Elf) !void {
2777 out.* = .{2771 var sizes = SymtabSize{};
2778 .st_name = sym.st_name,2772
2779 .st_value = @as(u32, @intCast(sym.st_value)),2773 if (self.zig_module_index) |index| {
2780 .st_size = @as(u32, @intCast(sym.st_size)),2774 const zig_module = self.file(index).?.zig_module;
2781 .st_info = sym.st_info,2775 zig_module.updateSymtabSize(self);
2782 .st_other = sym.st_other,2776 sizes.nlocals += zig_module.output_symtab_size.nlocals;
2783 .st_shndx = sym.st_shndx,2777 sizes.nglobals += zig_module.output_symtab_size.nglobals;
2784 };2778 }
2785}2779
2780 const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
2781 shdr.sh_info = sizes.nlocals + 1;
2782 self.markDirty(self.symtab_section_index.?, null);
27862783
2787fn writeSymbols(self: *Elf) !void {
2788 const gpa = self.base.allocator;
2789 const sym_size: u64 = switch (self.ptr_width) {2784 const sym_size: u64 = switch (self.ptr_width) {
2790 .p32 => @sizeOf(elf.Elf32_Sym),2785 .p32 => @sizeOf(elf.Elf32_Sym),
2791 .p64 => @sizeOf(elf.Elf64_Sym),2786 .p64 => @sizeOf(elf.Elf64_Sym),
...@@ -2794,59 +2789,61 @@ fn writeSymbols(self: *Elf) !void {...@@ -2794,59 +2789,61 @@ fn writeSymbols(self: *Elf) !void {
2794 .p32 => @alignOf(elf.Elf32_Sym),2789 .p32 => @alignOf(elf.Elf32_Sym),
2795 .p64 => @alignOf(elf.Elf64_Sym),2790 .p64 => @alignOf(elf.Elf64_Sym),
2796 };2791 };
2797 const zig_module = self.file(self.zig_module_index.?).?.zig_module;2792 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
2793 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
2794}
27982795
2796fn writeSymtab(self: *Elf) !void {
2797 const gpa = self.base.allocator;
2799 const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];2798 const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
2800 shdr.sh_info = @intCast(zig_module.locals().len);2799 const sym_size: u64 = switch (self.ptr_width) {
2801 self.markDirty(self.symtab_section_index.?, null);2800 .p32 => @sizeOf(elf.Elf32_Sym),
2801 .p64 => @sizeOf(elf.Elf64_Sym),
2802 };
2803 const nsyms = @divExact(shdr.sh_size, sym_size);
28022804
2803 const nsyms = zig_module.locals().len + zig_module.globals().len;2805 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, shdr.sh_offset });
2804 const needed_size = nsyms * sym_size;2806
2805 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);2807 const symtab = try gpa.alloc(elf.Elf64_Sym, nsyms);
2808 defer gpa.free(symtab);
2809
2810 var ctx: struct { ilocal: usize, iglobal: usize, symtab: []elf.Elf64_Sym } = .{
2811 .ilocal = 1,
2812 .iglobal = shdr.sh_info,
2813 .symtab = symtab,
2814 };
2815
2816 if (self.zig_module_index) |index| {
2817 const zig_module = self.file(index).?.zig_module;
2818 zig_module.writeSymtab(self, ctx);
2819 ctx.ilocal += zig_module.output_symtab_size.nlocals;
2820 ctx.iglobal += zig_module.output_symtab_size.nglobals;
2821 }
28062822
2807 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();2823 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
2808 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, shdr.sh_offset });
2809 switch (self.ptr_width) {2824 switch (self.ptr_width) {
2810 .p32 => {2825 .p32 => {
2811 const buf = try gpa.alloc(elf.Elf32_Sym, nsyms);2826 const buf = try gpa.alloc(elf.Elf32_Sym, symtab.len);
2812 defer gpa.free(buf);2827 defer gpa.free(buf);
28132828
2814 for (buf[0..zig_module.locals().len], zig_module.locals()) |*sym, local_index| {2829 for (buf, symtab) |*out, sym| {
2815 const local = self.symbol(local_index);2830 out.* = .{
2816 elf32SymFromSym(local.sourceSymbol(self).*, sym);2831 .st_name = sym.st_name,
2817 if (foreign_endian) {2832 .st_info = sym.st_info,
2818 mem.byteSwapAllFields(elf.Elf32_Sym, sym);2833 .st_other = sym.st_other,
2819 }2834 .st_shndx = sym.st_shndx,
2820 }2835 .st_value = @as(u32, @intCast(sym.st_value)),
28212836 .st_size = @as(u32, @intCast(sym.st_size)),
2822 for (buf[zig_module.locals().len..], zig_module.globals()) |*sym, global_index| {2837 };
2823 const global = self.symbol(global_index);2838 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
2824 elf32SymFromSym(global.sourceSymbol(self).*, sym);
2825 if (foreign_endian) {
2826 mem.byteSwapAllFields(elf.Elf32_Sym, sym);
2827 }
2828 }2839 }
2829 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);2840 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);
2830 },2841 },
2831 .p64 => {2842 .p64 => {
2832 const buf = try gpa.alloc(elf.Elf64_Sym, nsyms);2843 if (foreign_endian) {
2833 defer gpa.free(buf);2844 for (symtab) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
2834 for (buf[0..zig_module.locals().len], zig_module.locals()) |*sym, local_index| {
2835 const local = self.symbol(local_index);
2836 sym.* = local.sourceSymbol(self).*;
2837 if (foreign_endian) {
2838 mem.byteSwapAllFields(elf.Elf64_Sym, sym);
2839 }
2840 }
2841
2842 for (buf[zig_module.locals().len..], zig_module.globals()) |*sym, global_index| {
2843 const global = self.symbol(global_index);
2844 sym.* = global.sourceSymbol(self).*;
2845 if (foreign_endian) {
2846 mem.byteSwapAllFields(elf.Elf64_Sym, sym);
2847 }
2848 }2845 }
2849 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);2846 try self.base.file.?.pwriteAll(mem.sliceAsBytes(symtab), shdr.sh_offset);
2850 },2847 },
2851 }2848 }
2852}2849}
...@@ -3282,7 +3279,19 @@ const DeclMetadata = struct {...@@ -3282,7 +3279,19 @@ const DeclMetadata = struct {
3282 }3279 }
3283};3280};
32843281
3285const Elf = @This();3282pub const SymtabSize = struct {
3283 nlocals: u32 = 0,
3284 nglobals: u32 = 0,
3285};
3286
3287pub const null_sym = elf.Elf64_Sym{
3288 .st_name = 0,
3289 .st_info = 0,
3290 .st_other = 0,
3291 .st_shndx = 0,
3292 .st_value = 0,
3293 .st_size = 0,
3294};
32863295
3287const std = @import("std");3296const std = @import("std");
3288const build_options = @import("build_options");3297const build_options = @import("build_options");
...@@ -3309,6 +3318,7 @@ pub const Atom = @import("Elf/Atom.zig");...@@ -3309,6 +3318,7 @@ pub const Atom = @import("Elf/Atom.zig");
3309const Cache = std.Build.Cache;3318const Cache = std.Build.Cache;
3310const Compilation = @import("../Compilation.zig");3319const Compilation = @import("../Compilation.zig");
3311const Dwarf = @import("Dwarf.zig");3320const Dwarf = @import("Dwarf.zig");
3321const Elf = @This();
3312const File = @import("Elf/file.zig").File;3322const File = @import("Elf/file.zig").File;
3313const LinkerDefined = @import("Elf/LinkerDefined.zig");3323const LinkerDefined = @import("Elf/LinkerDefined.zig");
3314const Liveness = @import("../Liveness.zig");3324const Liveness = @import("../Liveness.zig");
src/link/Elf/Symbol.zig+7-6
...@@ -35,7 +35,8 @@ extra_index: u32 = 0,...@@ -35,7 +35,8 @@ extra_index: u32 = 0,
35pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {35pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
36 const file_ptr = symbol.file(elf_file).?;36 const file_ptr = symbol.file(elf_file).?;
37 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;37 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
38 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and file_ptr != .linker_defined and file_ptr != .zig_module;38 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and
39 file_ptr != .linker_defined and file_ptr != .zig_module;
39}40}
4041
41pub fn isLocal(symbol: Symbol) bool {42pub fn isLocal(symbol: Symbol) bool {
...@@ -169,7 +170,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {...@@ -169,7 +170,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
169 elf_file.setSymbolExtra(symbol.extra_index, extras);170 elf_file.setSymbolExtra(symbol.extra_index, extras);
170}171}
171172
172pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {173pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
173 const file_ptr = symbol.file(elf_file).?;174 const file_ptr = symbol.file(elf_file).?;
174 const s_sym = symbol.sourceSymbol(elf_file);175 const s_sym = symbol.sourceSymbol(elf_file);
175 const st_type = symbol.type(elf_file);176 const st_type = symbol.type(elf_file);
...@@ -184,7 +185,7 @@ pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {...@@ -184,7 +185,7 @@ pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {
184 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;185 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
185 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module)186 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module)
186 break :blk elf.SHN_ABS;187 break :blk elf.SHN_ABS;
187 break :blk symbol.shndx;188 break :blk symbol.output_section_index;
188 };189 };
189 const st_value = blk: {190 const st_value = blk: {
190 // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);191 // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);
...@@ -197,8 +198,8 @@ pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {...@@ -197,8 +198,8 @@ pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {
197 // if (Elf.shdrIsTls(shdr)) break :blk symbol.value - elf_file.getTlsAddress();198 // if (Elf.shdrIsTls(shdr)) break :blk symbol.value - elf_file.getTlsAddress();
198 break :blk symbol.value;199 break :blk symbol.value;
199 };200 };
200 return elf.Elf64_Sym{201 out.* = .{
201 .st_name = st_name,202 .st_name = symbol.name_offset,
202 .st_info = (st_bind << 4) | st_type,203 .st_info = (st_bind << 4) | st_type,
203 .st_other = s_sym.st_other,204 .st_other = s_sym.st_other,
204 .st_shndx = st_shndx,205 .st_shndx = st_shndx,
...@@ -343,9 +344,9 @@ pub const Extra = struct {...@@ -343,9 +344,9 @@ pub const Extra = struct {
343344
344pub const Index = u32;345pub const Index = u32;
345346
346const std = @import("std");
347const assert = std.debug.assert;347const assert = std.debug.assert;
348const elf = std.elf;348const elf = std.elf;
349const std = @import("std");
349350
350const Atom = @import("Atom.zig");351const Atom = @import("Atom.zig");
351const Elf = @import("../Elf.zig");352const Elf = @import("../Elf.zig");
src/link/Elf/ZigModule.zig+63-18
...@@ -10,7 +10,7 @@ atoms: std.ArrayListUnmanaged(Atom.Index) = .{},...@@ -10,7 +10,7 @@ atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
1010
11alive: bool = true,11alive: bool = true,
1212
13// output_symtab_size: Elf.SymtabSize = .{},13output_symtab_size: Elf.SymtabSize = .{},
1414
15pub fn deinit(self: *ZigModule, allocator: Allocator) void {15pub fn deinit(self: *ZigModule, allocator: Allocator) void {
16 self.elf_local_symbols.deinit(allocator);16 self.elf_local_symbols.deinit(allocator);
...@@ -36,14 +36,9 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !...@@ -36,14 +36,9 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !
36 symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len));36 symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len));
3737
38 const local_esym = try self.elf_local_symbols.addOne(gpa);38 const local_esym = try self.elf_local_symbols.addOne(gpa);
39 local_esym.* = .{39 local_esym.* = Elf.null_sym;
40 .st_name = 0,40 local_esym.st_info = elf.STB_LOCAL << 4;
41 .st_info = elf.STB_LOCAL << 4,41 local_esym.st_shndx = output_section_index;
42 .st_other = 0,
43 .st_shndx = output_section_index,
44 .st_value = 0,
45 .st_size = 0,
46 };
4742
48 try self.atoms.append(gpa, atom_index);43 try self.atoms.append(gpa, atom_index);
49 try self.local_symbols.putNoClobber(gpa, symbol_index, {});44 try self.local_symbols.putNoClobber(gpa, symbol_index, {});
...@@ -57,22 +52,73 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I...@@ -57,22 +52,73 @@ pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.I
57 try self.global_symbols.ensureUnusedCapacity(gpa, 1);52 try self.global_symbols.ensureUnusedCapacity(gpa, 1);
58 const off = try elf_file.strtab.insert(gpa, name);53 const off = try elf_file.strtab.insert(gpa, name);
59 const esym_index = @as(Symbol.Index, @intCast(self.elf_global_symbols.items.len));54 const esym_index = @as(Symbol.Index, @intCast(self.elf_global_symbols.items.len));
60 self.elf_global_symbols.appendAssumeCapacity(.{55 const esym = self.elf_global_symbols.addOneAssumeCapacity();
61 .st_name = off,56 esym.* = Elf.null_sym;
62 .st_info = elf.STB_GLOBAL << 4,57 esym.st_name = off;
63 .st_other = 0,58 esym.st_info = elf.STB_GLOBAL << 4;
64 .st_shndx = 0,
65 .st_value = 0,
66 .st_size = 0,
67 });
68 const gop = try elf_file.getOrPutGlobal(off);59 const gop = try elf_file.getOrPutGlobal(off);
69 const sym = elf_file.symbol(gop.index);60 const sym = elf_file.symbol(gop.index);
70 sym.file_index = self.index;61 sym.file_index = self.index;
71 sym.esym_index = esym_index;62 sym.esym_index = esym_index;
63 sym.flags.@"export" = true;
72 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});64 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});
73 return gop.index;65 return gop.index;
74}66}
7567
68pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
69 for (self.locals()) |local_index| {
70 const local = elf_file.symbol(local_index);
71 const esym = self.sourceSymbol(local_index, elf_file);
72 switch (esym.st_type()) {
73 elf.STT_SECTION, elf.STT_NOTYPE => {
74 local.flags.output_symtab = false;
75 continue;
76 },
77 else => {},
78 }
79 local.flags.output_symtab = true;
80 self.output_symtab_size.nlocals += 1;
81 }
82
83 for (self.globals()) |global_index| {
84 const global = elf_file.symbol(global_index);
85 if (global.file(elf_file)) |file| if (file.index() != self.index) {
86 global.flags.output_symtab = false;
87 continue;
88 };
89 global.flags.output_symtab = true;
90 if (global.isLocal()) {
91 self.output_symtab_size.nlocals += 1;
92 } else {
93 self.output_symtab_size.nglobals += 1;
94 }
95 }
96}
97
98pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
99 var ilocal = ctx.ilocal;
100 for (self.locals()) |local_index| {
101 const local = elf_file.symbol(local_index);
102 if (!local.flags.output_symtab) continue;
103 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
104 ilocal += 1;
105 }
106
107 var iglobal = ctx.iglobal;
108 for (self.globals()) |global_index| {
109 const global = elf_file.symbol(global_index);
110 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
111 if (!global.flags.output_symtab) continue;
112 if (global.isLocal()) {
113 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
114 ilocal += 1;
115 } else {
116 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
117 iglobal += 1;
118 }
119 }
120}
121
76pub fn sourceSymbol(self: *ZigModule, symbol_index: Symbol.Index, elf_file: *Elf) *elf.Elf64_Sym {122pub fn sourceSymbol(self: *ZigModule, symbol_index: Symbol.Index, elf_file: *Elf) *elf.Elf64_Sym {
77 const sym = elf_file.symbol(symbol_index);123 const sym = elf_file.symbol(symbol_index);
78 if (self.local_symbols.get(symbol_index)) |_| return &self.elf_local_symbols.items[sym.esym_index];124 if (self.local_symbols.get(symbol_index)) |_| return &self.elf_local_symbols.items[sym.esym_index];
...@@ -134,5 +180,4 @@ const Elf = @import("../Elf.zig");...@@ -134,5 +180,4 @@ const Elf = @import("../Elf.zig");
134const File = @import("file.zig").File;180const File = @import("file.zig").File;
135const Module = @import("../../Module.zig");181const Module = @import("../../Module.zig");
136const ZigModule = @This();182const ZigModule = @This();
137// const Object = @import("Object.zig");
138const Symbol = @import("Symbol.zig");183const Symbol = @import("Symbol.zig");