diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-07 03:22:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-07 03:22:14 +0100 |
| commit | bf0387b6bb9c65c30f14e699a2f2cfbfea27184e (patch) | |
| tree | c0d68c1f225ed91cc900475958d1c125ae3239fb /src | |
| parent | 234693bcbba6f55ff6e975ddbedf0fad4dfaa8f1 (diff) | |
| parent | 261db02018c71e8977d2bf2a78d495cc31abd1bc (diff) | |
| download | zig-bf0387b6bb9c65c30f14e699a2f2cfbfea27184e.tar.gz zig-bf0387b6bb9c65c30f14e699a2f2cfbfea27184e.zip | |
Merge pull request #17873 from ziglang/elf-archive
elf: implement archiving input object files
Diffstat (limited to 'src')
| -rw-r--r-- | src/Compilation.zig | 10 | ||||
| -rw-r--r-- | src/link/Elf.zig | 158 | ||||
| -rw-r--r-- | src/link/Elf/Archive.zig | 121 | ||||
| -rw-r--r-- | src/link/Elf/Object.zig | 34 | ||||
| -rw-r--r-- | src/link/Elf/SharedObject.zig | 3 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 27 | ||||
| -rw-r--r-- | src/link/Elf/file.zig | 37 |
7 files changed, 228 insertions, 162 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index c2a48f57ff..c8618154d9 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2304,10 +2304,16 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void defer comp.gpa.free(o_sub_path); // Work around windows `AccessDenied` if any files within this directory are open - // by doing the makeExecutable/makeWritable dance. + // by closing and reopening the file handles. const need_writable_dance = builtin.os.tag == .windows and comp.bin_file.file != null; if (need_writable_dance) { - try comp.bin_file.makeExecutable(); + // We cannot just call `makeExecutable` as it makes a false assumption that we have a + // file handle open only when linking an executable file. This used to be true when + // our linkers were incapable of emitting relocatables and static archive. Now that + // they are capable, we need to unconditionally close the file handle and re-open it + // in the follow up call to `makeWritable`. + comp.bin_file.file.?.close(); + comp.bin_file.file = null; } try comp.bin_file.renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 7311bd38b4..f4b9b5ff33 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -288,7 +288,9 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option const index = @as(File.Index, @intCast(try self.files.addOne(allocator))); self.files.set(index, .{ .zig_object = .{ .index = index, - .path = options.module.?.main_mod.root_src_path, + .path = try std.fmt.allocPrint(self.base.allocator, "{s}.o", .{std.fs.path.stem( + options.module.?.main_mod.root_src_path, + )}), } }); self.zig_object_index = index; try self.zigObjectPtr().?.init(self); @@ -940,14 +942,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } else null; const gc_sections = self.base.options.gc_sections orelse false; - if (self.isRelocatable() and self.zig_object_index == null) { - if (self.isStaticLib()) { - var err = try self.addErrorWithNotes(0); - try err.addMsg(self, "fatal linker error: emitting static libs unimplemented", .{}); - return; - } + if (self.isObject() and self.zig_object_index == null) { // TODO this will become -r route I guess. For now, just copy the object file. - assert(self.base.file == null); // TODO uncomment once we implement -r const the_object_path = blk: { if (self.base.options.objects.len != 0) { break :blk self.base.options.objects[0].path; @@ -1287,8 +1283,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try positionals.append(.{ .path = ssp.full_object_path }); } - if (self.isStaticLib()) return self.flushStaticLib(comp, positionals.items); - for (positionals.items) |obj| { var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err| @@ -1394,6 +1388,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try self.handleAndReportParseError(obj.path, err, &parse_ctx); } + if (self.isStaticLib()) return self.flushStaticLib(comp); + + // Init all objects + for (self.objects.items) |index| { + try self.file(index).?.object.init(self); + } + for (self.shared_objects.items) |index| { + try self.file(index).?.shared_object.init(self); + } + // Dedup shared objects { var seen_dsos = std.StringHashMap(void).init(gpa); @@ -1523,18 +1527,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } } -pub fn flushStaticLib( - self: *Elf, - comp: *Compilation, - positionals: []const Compilation.LinkObject, -) link.File.FlushError!void { +pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void { _ = comp; - if (positionals.len > 0) { - var err = try self.addErrorWithNotes(1); - try err.addMsg(self, "fatal linker error: too many input positionals", .{}); - try err.addNote(self, "TODO implement linking objects into an static library", .{}); - return; - } const gpa = self.base.allocator; // First, we flush relocatable object file generated with our backends. @@ -1546,27 +1540,33 @@ pub fn flushStaticLib( try self.initShStrtab(); try self.sortShdrs(); zig_object.updateRelaSectionSizes(self); - try self.updateSymtabSize(); + self.updateSymtabSizeObject(zig_object); self.updateShStrtabSize(); try self.allocateNonAllocSections(); try self.writeShdrTable(); try zig_object.writeRelaSections(self); - try self.writeSymtab(); + try self.writeSymtabObject(zig_object); try self.writeShStrtab(); try self.writeElfHeader(); } - // TODO parse positionals that we want to make part of the archive - - // TODO update ar symtab from parsed positionals + var files = std.ArrayList(File.Index).init(gpa); + defer files.deinit(); + try files.ensureTotalCapacityPrecise(self.objects.items.len + 1); + // Note to self: we currently must have ZigObject written out first as we write the object + // file into the same file descriptor and then re-read its contents. + // TODO implement writing ZigObject to a buffer instead of file. + if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index); + for (self.objects.items) |index| files.appendAssumeCapacity(index); + // Update ar symtab from parsed objects var ar_symtab: Archive.ArSymtab = .{}; defer ar_symtab.deinit(gpa); - if (self.zigObjectPtr()) |zig_object| { - try zig_object.updateArSymtab(&ar_symtab, self); + for (files.items) |index| { + try self.file(index).?.updateArSymtab(&ar_symtab, self); } ar_symtab.sort(); @@ -1575,25 +1575,32 @@ pub fn flushStaticLib( var ar_strtab: Archive.ArStrtab = .{}; defer ar_strtab.deinit(gpa); - if (self.zigObjectPtr()) |zig_object| { - try zig_object.updateArStrtab(gpa, &ar_strtab); - zig_object.updateArSize(self); + for (files.items) |index| { + const file_ptr = self.file(index).?; + try file_ptr.updateArStrtab(gpa, &ar_strtab); + file_ptr.updateArSize(self); } // Update file offsets of contributing objects. const total_size: usize = blk: { - var pos: usize = Archive.SARMAG; - pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64); + var pos: usize = elf.ARMAG.len; + pos += @sizeOf(elf.ar_hdr) + ar_symtab.size(.p64); if (ar_strtab.size() > 0) { pos = mem.alignForward(usize, pos, 2); - pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size(); + pos += @sizeOf(elf.ar_hdr) + ar_strtab.size(); } - if (self.zigObjectPtr()) |zig_object| { + for (files.items) |index| { + const file_ptr = self.file(index).?; + const state = switch (file_ptr) { + .zig_object => |x| &x.output_ar_state, + .object => |x| &x.output_ar_state, + else => unreachable, + }; pos = mem.alignForward(usize, pos, 2); - zig_object.output_ar_state.file_off = pos; - pos += @sizeOf(Archive.ar_hdr) + (math.cast(usize, zig_object.output_ar_state.size) orelse return error.Overflow); + state.file_off = pos; + pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow); } break :blk pos; @@ -1609,7 +1616,7 @@ pub fn flushStaticLib( try buffer.ensureTotalCapacityPrecise(total_size); // Write magic - try buffer.writer().writeAll(Archive.ARMAG); + try buffer.writer().writeAll(elf.ARMAG); // Write symtab try ar_symtab.write(.p64, self, buffer.writer()); @@ -1621,9 +1628,9 @@ pub fn flushStaticLib( } // Write object files - if (self.zigObjectPtr()) |zig_object| { + for (files.items) |index| { if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); - try zig_object.writeAr(self, buffer.writer()); + try self.file(index).?.writeAr(self, buffer.writer()); } assert(buffer.items.len == total_size); @@ -4054,7 +4061,7 @@ fn updateSectionSizes(self: *Elf) !void { self.shdrs.items[index].sh_size = self.verneed.size(); } - try self.updateSymtabSize(); + self.updateSymtabSize(); self.updateShStrtabSize(); } @@ -4477,7 +4484,7 @@ fn writeAtoms(self: *Elf) !void { try self.reportUndefined(&undefs); } -fn updateSymtabSize(self: *Elf) !void { +fn updateSymtabSize(self: *Elf) void { var sizes = SymtabSize{}; if (self.zigObjectPtr()) |zig_object| { @@ -4538,6 +4545,25 @@ fn updateSymtabSize(self: *Elf) !void { strtab.sh_size = sizes.strsize + 1; } +fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void { + zig_object.asFile().updateSymtabSize(self); + const sizes = zig_object.output_symtab_size; + + const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?]; + symtab_shdr.sh_info = sizes.nlocals + 1; + symtab_shdr.sh_link = self.strtab_section_index.?; + + const sym_size: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Sym), + .p64 => @sizeOf(elf.Elf64_Sym), + }; + const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; + symtab_shdr.sh_size = needed_size; + + const strtab = &self.shdrs.items[self.strtab_section_index.?]; + strtab.sh_size = sizes.strsize + 1; +} + fn writeSyntheticSections(self: *Elf) !void { const gpa = self.base.allocator; @@ -4782,6 +4808,54 @@ fn writeSymtab(self: *Elf) !void { try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset); } +fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void { + const gpa = self.base.allocator; + const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; + const strtab_shdr = self.shdrs.items[self.strtab_section_index.?]; + const sym_size: u64 = switch (self.ptr_width) { + .p32 => @sizeOf(elf.Elf32_Sym), + .p64 => @sizeOf(elf.Elf64_Sym), + }; + const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow; + + log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset }); + + try self.symtab.resize(gpa, nsyms); + const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow; + try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size); + + zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info }); + + const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); + switch (self.ptr_width) { + .p32 => { + const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len); + defer gpa.free(buf); + + for (buf, self.symtab.items) |*out, sym| { + out.* = .{ + .st_name = sym.st_name, + .st_info = sym.st_info, + .st_other = sym.st_other, + .st_shndx = sym.st_shndx, + .st_value = @as(u32, @intCast(sym.st_value)), + .st_size = @as(u32, @intCast(sym.st_size)), + }; + if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out); + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset); + }, + .p64 => { + if (foreign_endian) { + for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym); + } + try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset); + }, + } + + try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset); +} + /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF. fn ptrWidthBytes(self: Elf) u8 { return switch (self.ptr_width) { diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 58a9e541a7..8e405e966c 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -8,8 +8,8 @@ pub fn isArchive(path: []const u8) !bool { const file = try std.fs.cwd().openFile(path, .{}); defer file.close(); const reader = file.reader(); - const magic = reader.readBytesNoEof(SARMAG) catch return false; - if (!mem.eql(u8, &magic, ARMAG)) return false; + const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false; + if (!mem.eql(u8, &magic, elf.ARMAG)) return false; return true; } @@ -24,21 +24,19 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { var stream = std.io.fixedBufferStream(self.data); const reader = stream.reader(); - _ = try reader.readBytesNoEof(SARMAG); + _ = try reader.readBytesNoEof(elf.ARMAG.len); while (true) { if (stream.pos >= self.data.len) break; + if (!mem.isAligned(stream.pos, 2)) stream.pos += 1; - if (stream.pos % 2 != 0) { - stream.pos += 1; - } - const hdr = try reader.readStruct(ar_hdr); + const hdr = try reader.readStruct(elf.ar_hdr); - if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { + if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { // TODO convert into an error log.debug( "{s}: invalid header delimiter: expected '{s}', found '{s}'", - .{ self.path, std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag) }, + .{ self.path, std.fmt.fmtSliceEscapeLower(elf.ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag) }, ); return; } @@ -48,28 +46,23 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { _ = stream.seekBy(size) catch {}; } - if (hdr.isSymtab()) continue; + if (hdr.isSymtab() or hdr.isSymtab64()) continue; if (hdr.isStrtab()) { self.strtab = self.data[stream.pos..][0..size]; continue; } + if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; - const name = ar_hdr.getValue(&hdr.ar_name); - - if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue; - - const object_name = blk: { - if (name[0] == '/') { - const off = try std.fmt.parseInt(u32, name[1..], 10); - const object_name = self.getString(off); - break :blk try gpa.dupe(u8, object_name[0 .. object_name.len - 1]); // To account for trailing '/' - } - break :blk try gpa.dupe(u8, name); - }; + const name = if (hdr.name()) |name| + try gpa.dupe(u8, name) + else if (try hdr.nameOffset()) |off| + try gpa.dupe(u8, self.getString(off)) + else + unreachable; const object = Object{ .archive = try gpa.dupe(u8, self.path), - .path = object_name, + .path = name, .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]), .index = undefined, .alive = false, @@ -83,7 +76,8 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void { fn getString(self: Archive, off: u32) []const u8 { assert(off < self.strtab.len); - return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0); + const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0); + return name[0 .. name.len - 1]; } pub fn setArHdr(opts: struct { @@ -94,8 +88,8 @@ pub fn setArHdr(opts: struct { name_off: u32, }, size: u32, -}) ar_hdr { - var hdr: ar_hdr = .{ +}) elf.ar_hdr { + var hdr: elf.ar_hdr = .{ .ar_name = undefined, .ar_date = undefined, .ar_uid = undefined, @@ -105,15 +99,15 @@ pub fn setArHdr(opts: struct { .ar_fmag = undefined, }; @memset(mem.asBytes(&hdr), 0x20); - @memcpy(&hdr.ar_fmag, Archive.ARFMAG); + @memcpy(&hdr.ar_fmag, elf.ARFMAG); { var stream = std.io.fixedBufferStream(&hdr.ar_name); const writer = stream.writer(); switch (opts.name) { - .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable, + .symtab => writer.print("{s}", .{elf.SYM64NAME}) catch unreachable, .strtab => writer.print("//", .{}) catch unreachable, - .name => |x| writer.print("{s}", .{x}) catch unreachable, + .name => |x| writer.print("{s}/", .{x}) catch unreachable, .name_off => |x| writer.print("/{d}", .{x}) catch unreachable, } } @@ -125,72 +119,8 @@ pub fn setArHdr(opts: struct { return hdr; } -// Archive files start with the ARMAG identifying string. Then follows a -// `struct ar_hdr', and as many bytes of member file data as its `ar_size' -// member indicates, for each member file. -/// String that begins an archive file. -pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n"; -/// Size of that string. -pub const SARMAG = 8; - -/// String in ar_fmag at the end of each header. -const ARFMAG: *const [2:0]u8 = "`\n"; - -/// Strtab identifier -const STRNAME: *const [2:0]u8 = "//"; - -/// 32-bit symtab identifier -const SYMNAME: *const [1:0]u8 = "/"; - -/// 64-bit symtab identifier -const SYM64NAME: *const [7:0]u8 = "/SYM64/"; - const strtab_delimiter = '\n'; - -pub const ar_hdr = extern struct { - /// Member file name, sometimes / terminated. - ar_name: [16]u8, - - /// File date, decimal seconds since Epoch. - ar_date: [12]u8, - - /// User ID, in ASCII format. - ar_uid: [6]u8, - - /// Group ID, in ASCII format. - ar_gid: [6]u8, - - /// File mode, in ASCII octal. - ar_mode: [8]u8, - - /// File size, in ASCII decimal. - ar_size: [10]u8, - - /// Always contains ARFMAG. - ar_fmag: [2]u8, - - fn date(self: ar_hdr) !u64 { - const value = getValue(&self.ar_date); - return std.fmt.parseInt(u64, value, 10); - } - - fn size(self: ar_hdr) !u32 { - const value = getValue(&self.ar_size); - return std.fmt.parseInt(u32, value, 10); - } - - fn getValue(raw: []const u8) []const u8 { - return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)}); - } - - fn isStrtab(self: ar_hdr) bool { - return mem.eql(u8, getValue(&self.ar_name), STRNAME); - } - - fn isSymtab(self: ar_hdr) bool { - return mem.eql(u8, getValue(&self.ar_name), SYMNAME) or mem.eql(u8, getValue(&self.ar_name), SYM64NAME); - } -}; +pub const max_member_name_len = 15; pub const ArSymtab = struct { symtab: std.ArrayListUnmanaged(Entry) = .{}, @@ -230,6 +160,9 @@ pub const ArSymtab = struct { if (elf_file.zigObjectPtr()) |zig_object| { offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off); } + for (elf_file.objects.items) |index| { + offsets.putAssumeCapacityNoClobber(index, elf_file.file(index).?.object.output_ar_state.file_off); + } // Number of symbols try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 968ff84853..e710a81ad3 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -20,6 +20,7 @@ alive: bool = true, num_dynrelocs: u32 = 0, output_symtab_size: Elf.SymtabSize = .{}, +output_ar_state: Archive.ArState = .{}, pub fn isObject(path: []const u8) !bool { const file = try std.fs.cwd().openFile(path, .{}); @@ -96,7 +97,9 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { sym.st_name + strtab_bias; } } +} +pub fn init(self: *Object, elf_file: *Elf) !void { try self.initAtoms(elf_file); try self.initSymtab(elf_file); @@ -651,6 +654,36 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void { } } +pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { + const gpa = elf_file.base.allocator; + const start = self.first_global orelse self.symtab.items.len; + + try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.symtab.items.len - start); + + for (self.symtab.items[start..]) |sym| { + if (sym.st_shndx == elf.SHN_UNDEF) continue; + const off = try ar_symtab.strtab.insert(gpa, self.getString(sym.st_name)); + ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index }); + } +} + +pub fn updateArSize(self: *Object) void { + self.output_ar_state.size = self.data.len; +} + +pub fn writeAr(self: Object, writer: anytype) !void { + const name = self.path; + const hdr = Archive.setArHdr(.{ + .name = if (name.len <= Archive.max_member_name_len) + .{ .name = name } + else + .{ .name_off = self.output_ar_state.name_off }, + .size = @intCast(self.data.len), + }); + try writer.writeAll(mem.asBytes(&hdr)); + try writer.writeAll(self.data); +} + pub fn locals(self: Object) []const Symbol.Index { const end = self.first_global orelse self.symbols.items.len; return self.symbols.items[0..end]; @@ -922,6 +955,7 @@ const math = std.math; const mem = std.mem; const Allocator = mem.Allocator; +const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); const Cie = eh_frame.Cie; const Elf = @import("../Elf.zig"); diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index 0924d3c761..1785232625 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -72,7 +72,6 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { } try self.parseVersions(elf_file); - try self.initSymtab(elf_file); } fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { @@ -120,7 +119,7 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { } } -fn initSymtab(self: *SharedObject, elf_file: *Elf) !void { +pub fn init(self: *SharedObject, elf_file: *Elf) !void { const gpa = elf_file.base.allocator; const symtab = self.getSymtabRaw(); const strtab = self.getStrtabRaw(); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index a6ac6cfc11..dd2126a99e 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -3,7 +3,6 @@ //! and any relocations that may have been emitted. //! Think about this as fake in-memory Object file for the Zig module. -/// Path is owned by Module and lives as long as *Module. path: []const u8, index: File.Index, @@ -78,7 +77,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { try self.atoms.append(gpa, 0); // null input section try self.strtab.buffer.append(gpa, 0); - const name_off = try self.strtab.insert(gpa, std.fs.path.stem(self.path)); + const name_off = try self.strtab.insert(gpa, self.path); const symbol_index = try elf_file.addSymbol(); try self.local_symbols.append(gpa, symbol_index); const symbol_ptr = elf_file.symbol(symbol_index); @@ -98,6 +97,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { } pub fn deinit(self: *ZigObject, allocator: Allocator) void { + allocator.free(self.path); self.local_esyms.deinit(allocator); self.global_esyms.deinit(allocator); self.strtab.deinit(allocator); @@ -512,25 +512,13 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: * 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; + if (global.outputShndx() == null) continue; const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file)); ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index }); } } -pub fn updateArStrtab( - self: *ZigObject, - allocator: Allocator, - ar_strtab: *Archive.ArStrtab, -) error{OutOfMemory}!void { - const name = try std.fmt.allocPrint(allocator, "{s}.o", .{std.fs.path.stem(self.path)}); - defer allocator.free(name); - if (name.len <= 15) return; - const name_off = try ar_strtab.insert(allocator, name); - self.output_ar_state.name_off = name_off; -} - pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void { var end_pos: u64 = elf_file.shdr_table_offset.?; for (elf_file.shdrs.items) |shdr| { @@ -549,11 +537,12 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void { const amt = try elf_file.base.file.?.preadAll(contents, 0); if (amt != self.output_ar_state.size) return error.InputOutput; - const name = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(self.path)}); - defer gpa.free(name); - + const name = self.path; const hdr = Archive.setArHdr(.{ - .name = if (name.len <= 15) .{ .name = name } else .{ .name_off = self.output_ar_state.name_off }, + .name = if (name.len <= Archive.max_member_name_len) + .{ .name = name } + else + .{ .name_off = self.output_ar_state.name_off }, .size = @intCast(size), }); try writer.writeAll(mem.asBytes(&hdr)); diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index e31170a178..cc0b486692 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -161,7 +161,7 @@ pub const File = union(enum) { } pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void { - var ilocal = ctx.ilocal; + var ilocal: usize = ctx.ilocal; for (file.locals()) |local_index| { const local = elf_file.symbol(local_index); if (!local.flags.output_symtab) continue; @@ -173,7 +173,7 @@ pub const File = union(enum) { ilocal += 1; } - var iglobal = ctx.iglobal; + var iglobal: usize = ctx.iglobal; for (file.globals()) |global_index| { const global = elf_file.symbol(global_index); const file_ptr = global.file(elf_file) orelse continue; @@ -199,7 +199,38 @@ pub const File = union(enum) { pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { return switch (file) { .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file), - .object => @panic("TODO"), + .object => |x| x.updateArSymtab(ar_symtab, elf_file), + inline else => unreachable, + }; + } + + pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void { + const path = switch (file) { + .zig_object => |x| x.path, + .object => |x| x.path, + inline else => unreachable, + }; + const state = switch (file) { + .zig_object => |x| &x.output_ar_state, + .object => |x| &x.output_ar_state, + inline else => unreachable, + }; + if (path.len <= Archive.max_member_name_len) return; + state.name_off = try ar_strtab.insert(allocator, path); + } + + pub fn updateArSize(file: File, elf_file: *Elf) void { + return switch (file) { + .zig_object => |x| x.updateArSize(elf_file), + .object => |x| x.updateArSize(), + inline else => unreachable, + }; + } + + pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void { + return switch (file) { + .zig_object => |x| x.writeAr(elf_file, writer), + .object => |x| x.writeAr(writer), inline else => unreachable, }; } |
