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
10431043 }
10441044 }
10451045
1046 try self.writeSymbols();
1046 try self.updateSymtabSize();
1047 try self.writeSymtab();
10471048
10481049 if (build_options.enable_logging) {
10491050 state_log.debug("{}", .{self.dumpState()});
......@@ -2662,14 +2663,7 @@ pub fn deleteDeclExport(
26622663 assert(self.resolver.fetchSwapRemove(sym.name_offset) != null); // TODO don't delete it if it's not dominant
26632664 sym.* = .{};
26642665 // TODO free list for esym!
2665 esym.* = .{
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 };
2666 esym.* = null_sym;
26732667 self.symbols_free_list.append(gpa, sym_index.*) catch {};
26742668 sym_index.* = 0;
26752669}
......@@ -2773,19 +2767,20 @@ fn writeOffsetTableEntry(self: *Elf, index: @TypeOf(self.got_table).Index) !void
27732767 }
27742768}
27752769
2776fn elf32SymFromSym(sym: elf.Elf64_Sym, out: *elf.Elf32_Sym) void {
2777 out.* = .{
2778 .st_name = sym.st_name,
2779 .st_value = @as(u32, @intCast(sym.st_value)),
2780 .st_size = @as(u32, @intCast(sym.st_size)),
2781 .st_info = sym.st_info,
2782 .st_other = sym.st_other,
2783 .st_shndx = sym.st_shndx,
2784 };
2785}
2770fn updateSymtabSize(self: *Elf) !void {
2771 var sizes = SymtabSize{};
2772
2773 if (self.zig_module_index) |index| {
2774 const zig_module = self.file(index).?.zig_module;
2775 zig_module.updateSymtabSize(self);
2776 sizes.nlocals += zig_module.output_symtab_size.nlocals;
2777 sizes.nglobals += zig_module.output_symtab_size.nglobals;
2778 }
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;
27892784 const sym_size: u64 = switch (self.ptr_width) {
27902785 .p32 => @sizeOf(elf.Elf32_Sym),
27912786 .p64 => @sizeOf(elf.Elf64_Sym),
......@@ -2794,59 +2789,61 @@ fn writeSymbols(self: *Elf) !void {
27942789 .p32 => @alignOf(elf.Elf32_Sym),
27952790 .p64 => @alignOf(elf.Elf64_Sym),
27962791 };
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;
27992798 const shdr = &self.sections.items(.shdr)[self.symtab_section_index.?];
2800 shdr.sh_info = @intCast(zig_module.locals().len);
2801 self.markDirty(self.symtab_section_index.?, null);
2799 const sym_size: u64 = switch (self.ptr_width) {
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;
2804 const needed_size = nsyms * sym_size;
2805 try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true);
2805 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, shdr.sh_offset });
2806
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
28072823 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 });
28092824 switch (self.ptr_width) {
28102825 .p32 => {
2811 const buf = try gpa.alloc(elf.Elf32_Sym, nsyms);
2826 const buf = try gpa.alloc(elf.Elf32_Sym, symtab.len);
28122827 defer gpa.free(buf);
28132828
2814 for (buf[0..zig_module.locals().len], zig_module.locals()) |*sym, local_index| {
2815 const local = self.symbol(local_index);
2816 elf32SymFromSym(local.sourceSymbol(self).*, sym);
2817 if (foreign_endian) {
2818 mem.byteSwapAllFields(elf.Elf32_Sym, sym);
2819 }
2820 }
2821
2822 for (buf[zig_module.locals().len..], zig_module.globals()) |*sym, global_index| {
2823 const global = self.symbol(global_index);
2824 elf32SymFromSym(global.sourceSymbol(self).*, sym);
2825 if (foreign_endian) {
2826 mem.byteSwapAllFields(elf.Elf32_Sym, sym);
2827 }
2829 for (buf, symtab) |*out, sym| {
2830 out.* = .{
2831 .st_name = sym.st_name,
2832 .st_info = sym.st_info,
2833 .st_other = sym.st_other,
2834 .st_shndx = sym.st_shndx,
2835 .st_value = @as(u32, @intCast(sym.st_value)),
2836 .st_size = @as(u32, @intCast(sym.st_size)),
2837 };
2838 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
28282839 }
28292840 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);
28302841 },
28312842 .p64 => {
2832 const buf = try gpa.alloc(elf.Elf64_Sym, nsyms);
2833 defer gpa.free(buf);
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 }
2843 if (foreign_endian) {
2844 for (symtab) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
28482845 }
2849 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), shdr.sh_offset);
2846 try self.base.file.?.pwriteAll(mem.sliceAsBytes(symtab), shdr.sh_offset);
28502847 },
28512848 }
28522849}
......@@ -3282,7 +3279,19 @@ const DeclMetadata = struct {
32823279 }
32833280};
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
32873296const std = @import("std");
32883297const build_options = @import("build_options");
......@@ -3309,6 +3318,7 @@ pub const Atom = @import("Elf/Atom.zig");
33093318const Cache = std.Build.Cache;
33103319const Compilation = @import("../Compilation.zig");
33113320const Dwarf = @import("Dwarf.zig");
3321const Elf = @This();
33123322const File = @import("Elf/file.zig").File;
33133323const LinkerDefined = @import("Elf/LinkerDefined.zig");
33143324const Liveness = @import("../Liveness.zig");
src/link/Elf/Symbol.zig+7-6
......@@ -35,7 +35,8 @@ extra_index: u32 = 0,
3535pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
3636 const file_ptr = symbol.file(elf_file).?;
3737 // 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;
3940}
4041
4142pub fn isLocal(symbol: Symbol) bool {
......@@ -169,7 +170,7 @@ pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
169170 elf_file.setSymbolExtra(symbol.extra_index, extras);
170171}
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 {
173174 const file_ptr = symbol.file(elf_file).?;
174175 const s_sym = symbol.sourceSymbol(elf_file);
175176 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 {
184185 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
185186 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module)
186187 break :blk elf.SHN_ABS;
187 break :blk symbol.shndx;
188 break :blk symbol.output_section_index;
188189 };
189190 const st_value = blk: {
190191 // 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 {
197198 // if (Elf.shdrIsTls(shdr)) break :blk symbol.value - elf_file.getTlsAddress();
198199 break :blk symbol.value;
199200 };
200 return elf.Elf64_Sym{
201 .st_name = st_name,
201 out.* = .{
202 .st_name = symbol.name_offset,
202203 .st_info = (st_bind << 4) | st_type,
203204 .st_other = s_sym.st_other,
204205 .st_shndx = st_shndx,
......@@ -343,9 +344,9 @@ pub const Extra = struct {
343344
344345pub const Index = u32;
345346
346const std = @import("std");
347347const assert = std.debug.assert;
348348const elf = std.elf;
349const std = @import("std");
349350
350351const Atom = @import("Atom.zig");
351352const Elf = @import("../Elf.zig");
src/link/Elf/ZigModule.zig+63-18
......@@ -10,7 +10,7 @@ atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
1010
1111alive: bool = true,
1212
13// output_symtab_size: Elf.SymtabSize = .{},
13output_symtab_size: Elf.SymtabSize = .{},
1414
1515pub fn deinit(self: *ZigModule, allocator: Allocator) void {
1616 self.elf_local_symbols.deinit(allocator);
......@@ -36,14 +36,9 @@ pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !
3636 symbol_ptr.esym_index = @as(Symbol.Index, @intCast(self.elf_local_symbols.items.len));
3737
3838 const local_esym = try self.elf_local_symbols.addOne(gpa);
39 local_esym.* = .{
40 .st_name = 0,
41 .st_info = elf.STB_LOCAL << 4,
42 .st_other = 0,
43 .st_shndx = output_section_index,
44 .st_value = 0,
45 .st_size = 0,
46 };
39 local_esym.* = Elf.null_sym;
40 local_esym.st_info = elf.STB_LOCAL << 4;
41 local_esym.st_shndx = output_section_index;
4742
4843 try self.atoms.append(gpa, atom_index);
4944 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
5752 try self.global_symbols.ensureUnusedCapacity(gpa, 1);
5853 const off = try elf_file.strtab.insert(gpa, name);
5954 const esym_index = @as(Symbol.Index, @intCast(self.elf_global_symbols.items.len));
60 self.elf_global_symbols.appendAssumeCapacity(.{
61 .st_name = off,
62 .st_info = elf.STB_GLOBAL << 4,
63 .st_other = 0,
64 .st_shndx = 0,
65 .st_value = 0,
66 .st_size = 0,
67 });
55 const esym = self.elf_global_symbols.addOneAssumeCapacity();
56 esym.* = Elf.null_sym;
57 esym.st_name = off;
58 esym.st_info = elf.STB_GLOBAL << 4;
6859 const gop = try elf_file.getOrPutGlobal(off);
6960 const sym = elf_file.symbol(gop.index);
7061 sym.file_index = self.index;
7162 sym.esym_index = esym_index;
63 sym.flags.@"export" = true;
7264 self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});
7365 return gop.index;
7466}
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
76122pub fn sourceSymbol(self: *ZigModule, symbol_index: Symbol.Index, elf_file: *Elf) *elf.Elf64_Sym {
77123 const sym = elf_file.symbol(symbol_index);
78124 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");
134180const File = @import("file.zig").File;
135181const Module = @import("../../Module.zig");
136182const ZigModule = @This();
137// const Object = @import("Object.zig");
138183const Symbol = @import("Symbol.zig");