diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-02 17:13:49 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-04 09:11:58 +0100 |
| commit | eddf9cc65b0abe8a8cdf8c80d8cd97e56e860515 (patch) | |
| tree | db856dac5e998e854d0050639cf798ca64d64865 /src/link | |
| parent | 481ee1b598b02cf5790ed12ed162a9f749a1ac92 (diff) | |
| download | zig-eddf9cc65b0abe8a8cdf8c80d8cd97e56e860515.tar.gz zig-eddf9cc65b0abe8a8cdf8c80d8cd97e56e860515.zip | |
elf: collect exports from ZigObject into AR symtab
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Elf.zig | 115 | ||||
| -rw-r--r-- | src/link/Elf/Archive.zig | 6 | ||||
| -rw-r--r-- | src/link/Elf/Symbol.zig | 6 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 16 | ||||
| -rw-r--r-- | src/link/Elf/file.zig | 10 |
5 files changed, 123 insertions, 30 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a10d17d75f..9e7fdf7b49 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -186,6 +186,12 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{} /// such as `resolver` and `comdat_groups_table`. strings: StringTable = .{}, +/// Static archive state. +/// TODO it may be wise to move it somewhere else, but for the time being, it +/// is far easier to pollute global state. +ar_symtab: std.ArrayListUnmanaged(struct { u32, File.Index }) = .{}, +ar_strtab: StringTable = .{}, + /// When allocating, the ideal_capacity is calculated by /// actual_capacity + (actual_capacity / ideal_factor) const ideal_factor = 3; @@ -392,6 +398,9 @@ pub fn deinit(self: *Elf) void { self.copy_rel.deinit(gpa); self.rela_dyn.deinit(gpa); self.rela_plt.deinit(gpa); + + self.ar_symtab.deinit(gpa); + self.ar_strtab.deinit(gpa); } pub 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 if (csu.crtend) |v| try positionals.append(.{ .path = v }); if (csu.crtn) |v| try positionals.append(.{ .path = v }); + if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); + if (self.isStaticLib()) return self.flushStaticLib(comp); + for (positionals.items) |obj| { var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err| try self.handleAndReportParseError(obj.path, err, &parse_ctx); } - if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); - if (self.isStaticLib()) return self.flushStaticLib(comp); - // Dedup shared objects { var seen_dsos = std.StringHashMap(void).init(gpa); @@ -1412,7 +1421,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // If we haven't already, create a linker-generated input file comprising of // linker-defined synthetic symbols only such as `_DYNAMIC`, etc. - if (self.linker_defined_index == null and !self.isObject()) { + if (self.linker_defined_index == null and !self.isRelocatable()) { const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); self.files.set(index, .{ .linker_defined = .{ .index = index } }); self.linker_defined_index = index; @@ -1517,14 +1526,55 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } else { log.debug("flushing. no_entry_point_found = false", .{}); self.error_flags.no_entry_point_found = false; - try self.writeHeader(); + try self.writeElfHeader(); } } pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void { _ = comp; - var err = try self.addErrorWithNotes(0); - try err.addMsg(self, "fatal linker error: emitting static libs unimplemented", .{}); + + // First, we flush relocatable object file generated with our backends. + if (self.zigObjectPtr()) |zig_object| { + zig_object.resolveSymbols(self); + zig_object.claimUnresolvedObject(self); + + try self.initSymtab(); + try self.initShStrtab(); + try self.sortShdrs(); + zig_object.updateRelaSectionSizes(self); + try self.updateSymtabSize(); + self.updateShStrtabSize(); + + try self.allocateNonAllocSections(); + + try self.writeShdrTable(); + try zig_object.writeRelaSections(self); + try self.writeSymtab(); + try self.writeShStrtab(); + try self.writeElfHeader(); + + // Update ar symbol and string tables. + try zig_object.asFile().updateArSymtab(self); + + for (self.ar_symtab.items, 0..) |entry, i| { + std.debug.print("{d}: {s} in {}\n", .{ + i, + self.ar_strtab.getAssumeExists(entry[0]), + self.file(entry[1]).?.fmtPath(), + }); + } + } + + // TODO parse positionals that we want to make part of the archive + + if (build_options.enable_logging) { + state_log.debug("{}", .{self.dumpState()}); + } + + // try self.writeArHdr(); + // TODO beyond this point I expect writing out objects parsed from the cmdline + + try self.writeArMagic(); } 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 { try self.writeShdrTable(); try self.writeSyntheticSections(); - try self.writeHeader(); + try self.writeElfHeader(); } const ParseError = error{ @@ -2797,7 +2847,7 @@ fn writePhdrTable(self: *Elf) !void { } } -fn writeHeader(self: *Elf) !void { +fn writeElfHeader(self: *Elf) !void { var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; var index: usize = 0; @@ -2918,6 +2968,15 @@ fn writeHeader(self: *Elf) !void { try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); } +fn writeArMagic(self: *Elf) !void { + // Magic bytes. + var buffer: [@as(usize, Archive.SARMAG) + 1]u8 = undefined; + var stream = std.io.fixedBufferStream(&buffer); + const writer = stream.writer(); + try writer.print("{s}\x00", .{Archive.ARMAG}); + try self.base.file.?.pwriteAll(&buffer, 0); +} + pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index); return self.zigObjectPtr().?.freeDecl(self, decl_index); @@ -3147,17 +3206,13 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { } fn initSections(self: *Elf) !void { - const small_ptr = switch (self.ptr_width) { - .p32 => true, - .p64 => false, - }; const ptr_size = self.ptrWidthBytes(); - if (!self.isStaticLib()) for (self.objects.items) |index| { + for (self.objects.items) |index| { try self.file(index).?.object.initOutputSections(self); - }; + } - const needs_eh_frame = if (self.isStaticLib()) false else for (self.objects.items) |index| { + const needs_eh_frame = for (self.objects.items) |index| { if (self.file(index).?.object.cies.items.len > 0) break true; } else false; if (needs_eh_frame) { @@ -3340,6 +3395,15 @@ fn initSections(self: *Elf) !void { } } + try self.initSymtab(); + try self.initShStrtab(); +} + +fn initSymtab(self: *Elf) !void { + const small_ptr = switch (self.ptr_width) { + .p32 => true, + .p64 => false, + }; if (self.symtab_section_index == null) { self.symtab_section_index = try self.addSection(.{ .name = ".symtab", @@ -3358,6 +3422,9 @@ fn initSections(self: *Elf) !void { .offset = std.math.maxInt(u64), }); } +} + +fn initShStrtab(self: *Elf) !void { if (self.shstrtab_section_index == null) { self.shstrtab_section_index = try self.addSection(.{ .name = ".shstrtab", @@ -3933,10 +4000,11 @@ fn updateSectionSizes(self: *Elf) !void { self.shdrs.items[index].sh_size = self.verneed.size(); } - if (self.symtab_section_index != null) { - try self.updateSymtabSize(); - } + try self.updateSymtabSize(); + self.updateShStrtabSize(); +} +fn updateShStrtabSize(self: *Elf) void { if (self.shstrtab_section_index) |index| { self.shdrs.items[index].sh_size = self.shstrtab.items.len; } @@ -4546,14 +4614,15 @@ fn writeSyntheticSections(self: *Elf) !void { try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset); } + try self.writeSymtab(); + try self.writeShStrtab(); +} + +fn writeShStrtab(self: *Elf) !void { if (self.shstrtab_section_index) |index| { const shdr = self.shdrs.items[index]; try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset); } - - if (self.symtab_section_index) |_| { - try self.writeSymtab(); - } } fn writeSymtab(self: *Elf) !void { diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 0eb2f2d404..1493ded684 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -13,11 +13,11 @@ pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n"; pub const SARMAG: u4 = 8; /// String in ar_fmag at the end of each header. -const ARFMAG: *const [2:0]u8 = "`\n"; +pub const ARFMAG: *const [2:0]u8 = "`\n"; -const SYM64NAME: *const [7:0]u8 = "/SYM64/"; +pub const SYM64NAME: *const [7:0]u8 = "/SYM64/"; -const ar_hdr = extern struct { +pub const ar_hdr = extern struct { /// Member file name, sometimes / terminated. ar_name: [16]u8, diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index b792725df7..13d9041813 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -43,7 +43,7 @@ pub fn outputShndx(symbol: Symbol) ?u16 { } pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool { - if (elf_file.isObject()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL; + if (elf_file.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL; return !(symbol.flags.import or symbol.flags.@"export"); } @@ -168,7 +168,7 @@ const GetOrCreateZigGotEntryResult = struct { }; pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult { - assert(!elf_file.isObject()); + assert(!elf_file.isRelocatable()); assert(symbol.flags.needs_zig_got); if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got }; 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 { if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?; if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; // TODO I think this is wrong and obsolete - if (elf_file.isObject() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?; + if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?; if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; break :blk symbol.outputShndx() orelse elf.SHN_UNDEF; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 5f6cc5488f..fd8de4002b 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -502,6 +502,22 @@ fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void { // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan); } +pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void { + const gpa = elf_file.base.allocator; + + try elf_file.ar_symtab.ensureUnusedCapacity(gpa, self.globals().len); + + for (self.globals()) |global_index| { + const global = elf_file.symbol(global_index); + const file_ptr = global.file(elf_file).?; + assert(file_ptr.index() == self.index); + if (global.type(elf_file) == elf.SHN_UNDEF) continue; + + const off = try elf_file.ar_strtab.insert(gpa, global.name(elf_file)); + elf_file.ar_symtab.appendAssumeCapacity(.{ off, self.index }); + } +} + pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void { _ = self; diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index a168ec541b..49d097ab61 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -136,7 +136,7 @@ pub const File = union(enum) { if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue; const esym = local.elfSym(elf_file); switch (esym.st_type()) { - elf.STT_SECTION => if (!elf_file.isObject()) continue, + elf.STT_SECTION => if (!elf_file.isRelocatable()) continue, elf.STT_NOTYPE => continue, else => {}, } @@ -196,6 +196,14 @@ pub const File = union(enum) { } } + pub fn updateArSymtab(file: File, elf_file: *Elf) !void { + return switch (file) { + .zig_object => |x| x.updateArSymtab(elf_file), + .object => @panic("TODO"), + inline else => unreachable, + }; + } + pub const Index = u32; pub const Entry = union(enum) { |
