authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-02 17:13:49+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-04 09:11:58+01:00
logeddf9cc65b0abe8a8cdf8c80d8cd97e56e860515
treedb856dac5e998e854d0050639cf798ca64d64865
parent481ee1b598b02cf5790ed12ed162a9f749a1ac92

elf: collect exports from ZigObject into AR symtab


5 files changed, 123 insertions(+), 30 deletions(-)

src/link/Elf.zig+92-23
...@@ -186,6 +186,12 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}...@@ -186,6 +186,12 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}
186/// such as `resolver` and `comdat_groups_table`.186/// such as `resolver` and `comdat_groups_table`.
187strings: StringTable = .{},187strings: StringTable = .{},
188188
189/// Static archive state.
190/// TODO it may be wise to move it somewhere else, but for the time being, it
191/// is far easier to pollute global state.
192ar_symtab: std.ArrayListUnmanaged(struct { u32, File.Index }) = .{},
193ar_strtab: StringTable = .{},
194
189/// When allocating, the ideal_capacity is calculated by195/// When allocating, the ideal_capacity is calculated by
190/// actual_capacity + (actual_capacity / ideal_factor)196/// actual_capacity + (actual_capacity / ideal_factor)
191const ideal_factor = 3;197const ideal_factor = 3;
...@@ -392,6 +398,9 @@ pub fn deinit(self: *Elf) void {...@@ -392,6 +398,9 @@ pub fn deinit(self: *Elf) void {
392 self.copy_rel.deinit(gpa);398 self.copy_rel.deinit(gpa);
393 self.rela_dyn.deinit(gpa);399 self.rela_dyn.deinit(gpa);
394 self.rela_plt.deinit(gpa);400 self.rela_plt.deinit(gpa);
401
402 self.ar_symtab.deinit(gpa);
403 self.ar_strtab.deinit(gpa);
395}404}
396405
397pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {406pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
...@@ -1383,15 +1392,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1383,15 +1392,15 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1383 if (csu.crtend) |v| try positionals.append(.{ .path = v });1392 if (csu.crtend) |v| try positionals.append(.{ .path = v });
1384 if (csu.crtn) |v| try positionals.append(.{ .path = v });1393 if (csu.crtn) |v| try positionals.append(.{ .path = v });
13851394
1395 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
1396 if (self.isStaticLib()) return self.flushStaticLib(comp);
1397
1386 for (positionals.items) |obj| {1398 for (positionals.items) |obj| {
1387 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1399 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1388 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|1400 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
1389 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1401 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1390 }1402 }
13911403
1392 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
1393 if (self.isStaticLib()) return self.flushStaticLib(comp);
1394
1395 // Dedup shared objects1404 // Dedup shared objects
1396 {1405 {
1397 var seen_dsos = std.StringHashMap(void).init(gpa);1406 var seen_dsos = std.StringHashMap(void).init(gpa);
...@@ -1412,7 +1421,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1412,7 +1421,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14121421
1413 // If we haven't already, create a linker-generated input file comprising of1422 // If we haven't already, create a linker-generated input file comprising of
1414 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.1423 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
1415 if (self.linker_defined_index == null and !self.isObject()) {1424 if (self.linker_defined_index == null and !self.isRelocatable()) {
1416 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1425 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1417 self.files.set(index, .{ .linker_defined = .{ .index = index } });1426 self.files.set(index, .{ .linker_defined = .{ .index = index } });
1418 self.linker_defined_index = index;1427 self.linker_defined_index = index;
...@@ -1517,14 +1526,55 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1517,14 +1526,55 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1517 } else {1526 } else {
1518 log.debug("flushing. no_entry_point_found = false", .{});1527 log.debug("flushing. no_entry_point_found = false", .{});
1519 self.error_flags.no_entry_point_found = false;1528 self.error_flags.no_entry_point_found = false;
1520 try self.writeHeader();1529 try self.writeElfHeader();
1521 }1530 }
1522}1531}
15231532
1524pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void {1533pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void {
1525 _ = comp;1534 _ = comp;
1526 var err = try self.addErrorWithNotes(0);1535
1527 try err.addMsg(self, "fatal linker error: emitting static libs unimplemented", .{});1536 // First, we flush relocatable object file generated with our backends.
1537 if (self.zigObjectPtr()) |zig_object| {
1538 zig_object.resolveSymbols(self);
1539 zig_object.claimUnresolvedObject(self);
1540
1541 try self.initSymtab();
1542 try self.initShStrtab();
1543 try self.sortShdrs();
1544 zig_object.updateRelaSectionSizes(self);
1545 try self.updateSymtabSize();
1546 self.updateShStrtabSize();
1547
1548 try self.allocateNonAllocSections();
1549
1550 try self.writeShdrTable();
1551 try zig_object.writeRelaSections(self);
1552 try self.writeSymtab();
1553 try self.writeShStrtab();
1554 try self.writeElfHeader();
1555
1556 // Update ar symbol and string tables.
1557 try zig_object.asFile().updateArSymtab(self);
1558
1559 for (self.ar_symtab.items, 0..) |entry, i| {
1560 std.debug.print("{d}: {s} in {}\n", .{
1561 i,
1562 self.ar_strtab.getAssumeExists(entry[0]),
1563 self.file(entry[1]).?.fmtPath(),
1564 });
1565 }
1566 }
1567
1568 // TODO parse positionals that we want to make part of the archive
1569
1570 if (build_options.enable_logging) {
1571 state_log.debug("{}", .{self.dumpState()});
1572 }
1573
1574 // try self.writeArHdr();
1575 // TODO beyond this point I expect writing out objects parsed from the cmdline
1576
1577 try self.writeArMagic();
1528}1578}
15291579
1530pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {1580pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {
...@@ -1543,7 +1593,7 @@ pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {...@@ -1543,7 +1593,7 @@ pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {
15431593
1544 try self.writeShdrTable();1594 try self.writeShdrTable();
1545 try self.writeSyntheticSections();1595 try self.writeSyntheticSections();
1546 try self.writeHeader();1596 try self.writeElfHeader();
1547}1597}
15481598
1549const ParseError = error{1599const ParseError = error{
...@@ -2797,7 +2847,7 @@ fn writePhdrTable(self: *Elf) !void {...@@ -2797,7 +2847,7 @@ fn writePhdrTable(self: *Elf) !void {
2797 }2847 }
2798}2848}
27992849
2800fn writeHeader(self: *Elf) !void {2850fn writeElfHeader(self: *Elf) !void {
2801 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;2851 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
28022852
2803 var index: usize = 0;2853 var index: usize = 0;
...@@ -2918,6 +2968,15 @@ fn writeHeader(self: *Elf) !void {...@@ -2918,6 +2968,15 @@ fn writeHeader(self: *Elf) !void {
2918 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2968 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
2919}2969}
29202970
2971fn writeArMagic(self: *Elf) !void {
2972 // Magic bytes.
2973 var buffer: [@as(usize, Archive.SARMAG) + 1]u8 = undefined;
2974 var stream = std.io.fixedBufferStream(&buffer);
2975 const writer = stream.writer();
2976 try writer.print("{s}\x00", .{Archive.ARMAG});
2977 try self.base.file.?.pwriteAll(&buffer, 0);
2978}
2979
2921pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {2980pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2922 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);2981 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
2923 return self.zigObjectPtr().?.freeDecl(self, decl_index);2982 return self.zigObjectPtr().?.freeDecl(self, decl_index);
...@@ -3147,17 +3206,13 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3147,17 +3206,13 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3147}3206}
31483207
3149fn initSections(self: *Elf) !void {3208fn initSections(self: *Elf) !void {
3150 const small_ptr = switch (self.ptr_width) {
3151 .p32 => true,
3152 .p64 => false,
3153 };
3154 const ptr_size = self.ptrWidthBytes();3209 const ptr_size = self.ptrWidthBytes();
31553210
3156 if (!self.isStaticLib()) for (self.objects.items) |index| {3211 for (self.objects.items) |index| {
3157 try self.file(index).?.object.initOutputSections(self);3212 try self.file(index).?.object.initOutputSections(self);
3158 };3213 }
31593214
3160 const needs_eh_frame = if (self.isStaticLib()) false else for (self.objects.items) |index| {3215 const needs_eh_frame = for (self.objects.items) |index| {
3161 if (self.file(index).?.object.cies.items.len > 0) break true;3216 if (self.file(index).?.object.cies.items.len > 0) break true;
3162 } else false;3217 } else false;
3163 if (needs_eh_frame) {3218 if (needs_eh_frame) {
...@@ -3340,6 +3395,15 @@ fn initSections(self: *Elf) !void {...@@ -3340,6 +3395,15 @@ fn initSections(self: *Elf) !void {
3340 }3395 }
3341 }3396 }
33423397
3398 try self.initSymtab();
3399 try self.initShStrtab();
3400}
3401
3402fn initSymtab(self: *Elf) !void {
3403 const small_ptr = switch (self.ptr_width) {
3404 .p32 => true,
3405 .p64 => false,
3406 };
3343 if (self.symtab_section_index == null) {3407 if (self.symtab_section_index == null) {
3344 self.symtab_section_index = try self.addSection(.{3408 self.symtab_section_index = try self.addSection(.{
3345 .name = ".symtab",3409 .name = ".symtab",
...@@ -3358,6 +3422,9 @@ fn initSections(self: *Elf) !void {...@@ -3358,6 +3422,9 @@ fn initSections(self: *Elf) !void {
3358 .offset = std.math.maxInt(u64),3422 .offset = std.math.maxInt(u64),
3359 });3423 });
3360 }3424 }
3425}
3426
3427fn initShStrtab(self: *Elf) !void {
3361 if (self.shstrtab_section_index == null) {3428 if (self.shstrtab_section_index == null) {
3362 self.shstrtab_section_index = try self.addSection(.{3429 self.shstrtab_section_index = try self.addSection(.{
3363 .name = ".shstrtab",3430 .name = ".shstrtab",
...@@ -3933,10 +4000,11 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3933,10 +4000,11 @@ fn updateSectionSizes(self: *Elf) !void {
3933 self.shdrs.items[index].sh_size = self.verneed.size();4000 self.shdrs.items[index].sh_size = self.verneed.size();
3934 }4001 }
39354002
3936 if (self.symtab_section_index != null) {4003 try self.updateSymtabSize();
3937 try self.updateSymtabSize();4004 self.updateShStrtabSize();
3938 }4005}
39394006
4007fn updateShStrtabSize(self: *Elf) void {
3940 if (self.shstrtab_section_index) |index| {4008 if (self.shstrtab_section_index) |index| {
3941 self.shdrs.items[index].sh_size = self.shstrtab.items.len;4009 self.shdrs.items[index].sh_size = self.shstrtab.items.len;
3942 }4010 }
...@@ -4546,14 +4614,15 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4546,14 +4614,15 @@ fn writeSyntheticSections(self: *Elf) !void {
4546 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);4614 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);
4547 }4615 }
45484616
4617 try self.writeSymtab();
4618 try self.writeShStrtab();
4619}
4620
4621fn writeShStrtab(self: *Elf) !void {
4549 if (self.shstrtab_section_index) |index| {4622 if (self.shstrtab_section_index) |index| {
4550 const shdr = self.shdrs.items[index];4623 const shdr = self.shdrs.items[index];
4551 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);4624 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
4552 }4625 }
4553
4554 if (self.symtab_section_index) |_| {
4555 try self.writeSymtab();
4556 }
4557}4626}
45584627
4559fn writeSymtab(self: *Elf) !void {4628fn writeSymtab(self: *Elf) !void {
src/link/Elf/Archive.zig+3-3
...@@ -13,11 +13,11 @@ pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";...@@ -13,11 +13,11 @@ pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";
13pub const SARMAG: u4 = 8;13pub const SARMAG: u4 = 8;
1414
15/// String in ar_fmag at the end of each header.15/// String in ar_fmag at the end of each header.
16const ARFMAG: *const [2:0]u8 = "`\n";16pub const ARFMAG: *const [2:0]u8 = "`\n";
1717
18const SYM64NAME: *const [7:0]u8 = "/SYM64/";18pub const SYM64NAME: *const [7:0]u8 = "/SYM64/";
1919
20const ar_hdr = extern struct {20pub const ar_hdr = extern struct {
21 /// Member file name, sometimes / terminated.21 /// Member file name, sometimes / terminated.
22 ar_name: [16]u8,22 ar_name: [16]u8,
2323
src/link/Elf/Symbol.zig+3-3
...@@ -43,7 +43,7 @@ pub fn outputShndx(symbol: Symbol) ?u16 {...@@ -43,7 +43,7 @@ pub fn outputShndx(symbol: Symbol) ?u16 {
43}43}
4444
45pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool {45pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool {
46 if (elf_file.isObject()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL;46 if (elf_file.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL;
47 return !(symbol.flags.import or symbol.flags.@"export");47 return !(symbol.flags.import or symbol.flags.@"export");
48}48}
4949
...@@ -168,7 +168,7 @@ const GetOrCreateZigGotEntryResult = struct {...@@ -168,7 +168,7 @@ const GetOrCreateZigGotEntryResult = struct {
168};168};
169169
170pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {170pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
171 assert(!elf_file.isObject());171 assert(!elf_file.isRelocatable());
172 assert(symbol.flags.needs_zig_got);172 assert(symbol.flags.needs_zig_got);
173 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };173 if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };
174 const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);174 const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
...@@ -220,7 +220,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -220,7 +220,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
220 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;220 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
221 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;221 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
222 // TODO I think this is wrong and obsolete222 // TODO I think this is wrong and obsolete
223 if (elf_file.isObject() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;223 if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;
224 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)224 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
225 break :blk elf.SHN_ABS;225 break :blk elf.SHN_ABS;
226 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;226 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
src/link/Elf/ZigObject.zig+16
...@@ -502,6 +502,22 @@ fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void {...@@ -502,6 +502,22 @@ fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void {
502 // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan);502 // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan);
503}503}
504504
505pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void {
506 const gpa = elf_file.base.allocator;
507
508 try elf_file.ar_symtab.ensureUnusedCapacity(gpa, self.globals().len);
509
510 for (self.globals()) |global_index| {
511 const global = elf_file.symbol(global_index);
512 const file_ptr = global.file(elf_file).?;
513 assert(file_ptr.index() == self.index);
514 if (global.type(elf_file) == elf.SHN_UNDEF) continue;
515
516 const off = try elf_file.ar_strtab.insert(gpa, global.name(elf_file));
517 elf_file.ar_symtab.appendAssumeCapacity(.{ off, self.index });
518 }
519}
520
505pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {521pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
506 _ = self;522 _ = self;
507523
src/link/Elf/file.zig+9-1
...@@ -136,7 +136,7 @@ pub const File = union(enum) {...@@ -136,7 +136,7 @@ pub const File = union(enum) {
136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
137 const esym = local.elfSym(elf_file);137 const esym = local.elfSym(elf_file);
138 switch (esym.st_type()) {138 switch (esym.st_type()) {
139 elf.STT_SECTION => if (!elf_file.isObject()) continue,139 elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,
140 elf.STT_NOTYPE => continue,140 elf.STT_NOTYPE => continue,
141 else => {},141 else => {},
142 }142 }
...@@ -196,6 +196,14 @@ pub const File = union(enum) {...@@ -196,6 +196,14 @@ pub const File = union(enum) {
196 }196 }
197 }197 }
198198
199 pub fn updateArSymtab(file: File, elf_file: *Elf) !void {
200 return switch (file) {
201 .zig_object => |x| x.updateArSymtab(elf_file),
202 .object => @panic("TODO"),
203 inline else => unreachable,
204 };
205 }
206
199 pub const Index = u32;207 pub const Index = u32;
200208
201 pub const Entry = union(enum) {209 pub const Entry = union(enum) {