diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-03 23:08:48 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-04 09:13:18 +0100 |
| commit | acd700ac6b4ec03412e2bac6aaf168f80f83f521 (patch) | |
| tree | 15c00fc6dfb8d7cd3fd9e7d2f53f460877ca6067 /src | |
| parent | ed2984f335bfaf7cc3cb7841554f4cbb958476dd (diff) | |
| download | zig-acd700ac6b4ec03412e2bac6aaf168f80f83f521.tar.gz zig-acd700ac6b4ec03412e2bac6aaf168f80f83f521.zip | |
elf: store ar state per input object file
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf.zig | 219 | ||||
| -rw-r--r-- | src/link/Elf/Archive.zig | 322 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 44 | ||||
| -rw-r--r-- | src/link/Elf/file.zig | 5 |
4 files changed, 347 insertions, 243 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig index daf952811d..75df6ce40a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -186,12 +186,6 @@ 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(ArSymtabEntry) = .{}, -ar_strtab: StringTable = .{}, - /// When allocating, the ideal_capacity is calculated by /// actual_capacity + (actual_capacity / ideal_factor) const ideal_factor = 3; @@ -398,9 +392,6 @@ 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 { @@ -1553,175 +1544,74 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void try self.writeSymtab(); try self.writeShStrtab(); try self.writeElfHeader(); - - // Update ar symbol table. - try zig_object.asFile().updateArSymtab(self); } // TODO parse positionals that we want to make part of the archive - mem.sort(ArSymtabEntry, self.ar_symtab.items, {}, ArSymtabEntry.lessThan); + // TODO update ar symtab from parsed positionals - if (build_options.enable_logging) { - state_log.debug("{}", .{self.dumpState()}); - } - - // Save object paths in filenames strtab. - var ar_strtab = std.ArrayList(u8).init(gpa); - defer ar_strtab.deinit(); - - var files = std.AutoHashMap(File.Index, struct { u32, u64, u64 }).init(gpa); - defer files.deinit(); - try files.ensureUnusedCapacity(@intCast(self.objects.items.len + 1)); + var ar_symtab: Archive.ArSymtab = .{}; + defer ar_symtab.deinit(gpa); if (self.zigObjectPtr()) |zig_object| { - const off = @as(u32, @intCast(ar_strtab.items.len)); - try ar_strtab.writer().print("{s}/\n", .{zig_object.path}); - files.putAssumeCapacityNoClobber(zig_object.index, .{ off, 0, 0 }); - } - - // Align to even byte boundary - { - const end = ar_strtab.items.len; - const aligned = mem.alignForward(usize, end, 2); - try ar_strtab.writer().writeByteNTimes(0, aligned - end); + try zig_object.updateArSymtab(&ar_symtab, self); } - // Encode ar symtab in 64bit format. - var ar_symtab = std.ArrayList(u8).init(gpa); - defer ar_symtab.deinit(); - try ar_symtab.ensureUnusedCapacity(8 * (self.ar_symtab.items.len + 1)); - - // Number of symbols - ar_symtab.writer().writeInt(u64, @as(u64, @intCast(self.ar_symtab.items.len)), .big) catch unreachable; + ar_symtab.sort(); - // Offsets which we will relocate later. - for (0..self.ar_symtab.items.len) |_| { - ar_symtab.writer().writeInt(u64, 0, .big) catch unreachable; - } + // Save object paths in filenames strtab. + var ar_strtab: Archive.ArStrtab = .{}; + defer ar_strtab.deinit(gpa); - // ASCII offsets into the strtab. - for (self.ar_symtab.items) |entry| { - const name = self.ar_strtab.getAssumeExists(entry.off); - try ar_symtab.writer().print("{s}\x00", .{name}); + if (self.zigObjectPtr()) |zig_object| { + try zig_object.updateArStrtab(gpa, &ar_strtab); + zig_object.updateArSize(self); } - // Align to 8 bytes if required - { - const end = ar_symtab.items.len; - const aligned = mem.alignForward(usize, end, 8); - try ar_symtab.writer().writeByteNTimes(0, aligned - end); - } + // Update file offsets of contributing objects. + const total_size: u64 = blk: { + var pos: u64 = Archive.SARMAG; + pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64); + pos = mem.alignForward(u64, pos, 2); + pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size(); - assert(mem.isAligned(ar_symtab.items.len, 8)); + if (self.zigObjectPtr()) |zig_object| { + pos = mem.alignForward(u64, pos, 2); + zig_object.output_ar_state.file_off = pos; + pos += @sizeOf(Archive.ar_hdr) + zig_object.output_ar_state.size; + } - // Calculate required size for headers before ZigObject pos in file. - if (self.zigObjectPtr()) |zig_object| { - var file_off: u64 = 0; - // Magic - file_off += Archive.SARMAG; - // Symtab - file_off += @sizeOf(Archive.ar_hdr) + @as(u64, @intCast(ar_symtab.items.len)); - // Strtab - file_off += @sizeOf(Archive.ar_hdr) + @as(u64, @intCast(ar_strtab.items.len)); - - const files_ptr = files.getPtr(zig_object.index).?; - files_ptr[1] = file_off; - - // Move ZigObject into place. - { - var end_pos: u64 = self.shdr_table_offset.?; - for (self.shdrs.items) |shdr| { - end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size); - } - const contents = try gpa.alloc(u8, end_pos); - defer gpa.free(contents); - const amt = try self.base.file.?.preadAll(contents, 0); - if (amt != end_pos) return error.InputOutput; - try self.base.file.?.pwriteAll(contents, file_off + @sizeOf(Archive.ar_hdr)); + break :blk pos; + }; - files_ptr[2] = end_pos; - } + if (build_options.enable_logging) { + state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)}); + state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); } - // Fixup file offsets in the symtab. - for (self.ar_symtab.items, 1..) |entry, i| { - const file_off = files.get(entry.file_index).?[1]; - mem.writeInt(u64, ar_symtab.items[8 * i ..][0..8], file_off, .big); - } + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + try buffer.ensureTotalCapacityPrecise(total_size); - var pos: usize = Archive.SARMAG; + // Write magic + try buffer.writer().writeAll(Archive.ARMAG); - // Write symtab. - { - const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar_symtab.items.len) }); - try self.base.file.?.pwriteAll(mem.asBytes(&hdr), pos); - pos += @sizeOf(Archive.ar_hdr); - try self.base.file.?.pwriteAll(ar_symtab.items, pos); - pos += ar_symtab.items.len; - } + // Write symtab + try ar_symtab.write(.p64, self, buffer.writer()); + if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); - // Write strtab. - { - const hdr = setArHdr(.{ - .kind = .strtab, - .name_off = 0, - .size = @intCast(ar_strtab.items.len), - }); - try self.base.file.?.pwriteAll(mem.asBytes(&hdr), pos); - pos += @sizeOf(Archive.ar_hdr); - try self.base.file.?.pwriteAll(ar_strtab.items, pos); - pos += ar_strtab.items.len; - } + // Write strtab + try ar_strtab.write(buffer.writer()); + if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); - // Zig object if defined + // Write object files if (self.zigObjectPtr()) |zig_object| { - const entry = files.get(zig_object.index).?; - const hdr = setArHdr(.{ .kind = .object, .name_off = entry[0], .size = @intCast(entry[2]) }); - try self.base.file.?.pwriteAll(mem.asBytes(&hdr), entry[1]); - pos += @sizeOf(Archive.ar_hdr) + entry[2]; + try zig_object.writeAr(self, buffer.writer()); } - // TODO parsed positionals + assert(buffer.items.len == total_size); - // Magic bytes. - { - try self.base.file.?.pwriteAll(Archive.ARMAG, 0); - } -} - -fn setArHdr(opts: struct { - kind: enum { symtab, strtab, object }, - name_off: u32, - size: u32, -}) Archive.ar_hdr { - var hdr: Archive.ar_hdr = .{ - .ar_name = undefined, - .ar_date = undefined, - .ar_uid = undefined, - .ar_gid = undefined, - .ar_mode = undefined, - .ar_size = undefined, - .ar_fmag = undefined, - }; - @memset(mem.asBytes(&hdr), 0x20); - @memcpy(&hdr.ar_fmag, Archive.ARFMAG); - - { - var stream = std.io.fixedBufferStream(&hdr.ar_name); - const writer = stream.writer(); - switch (opts.kind) { - .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable, - .strtab => writer.print("//", .{}) catch unreachable, - .object => writer.print("/{d}", .{opts.name_off}) catch unreachable, - } - } - { - var stream = std.io.fixedBufferStream(&hdr.ar_size); - stream.writer().print("{d}", .{opts.size}) catch unreachable; - } - - return hdr; + try self.base.file.?.pwriteAll(buffer.items, 0); } pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void { @@ -5822,18 +5712,6 @@ fn fmtDumpState( try writer.print("{}\n", .{self.got.fmt(self)}); try writer.print("{}\n", .{self.zig_got.fmt(self)}); - if (self.isStaticLib()) { - try writer.writeAll("ar symtab\n"); - for (self.ar_symtab.items, 0..) |entry, i| { - try writer.print(" {d} : {s} in file({d})\n", .{ - i, - self.ar_strtab.getAssumeExists(entry.off), - entry.file_index, - }); - } - try writer.writeByte('\n'); - } - try writer.writeAll("Output shdrs\n"); for (self.shdrs.items, 0..) |shdr, shndx| { try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{ @@ -5966,19 +5844,6 @@ const LastAtomAndFreeList = struct { const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList); -const ArSymtabEntry = struct { - off: u32, - file_index: File.Index, - - pub fn lessThan(ctx: void, lhs: ArSymtabEntry, rhs: ArSymtabEntry) bool { - _ = ctx; - if (lhs.off == rhs.off) { - return lhs.file_index < rhs.file_index; - } - return lhs.off < rhs.off; - } -}; - pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1; pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2; diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 2083171ce7..59576312e8 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -4,69 +4,11 @@ data: []const u8, objects: std.ArrayListUnmanaged(Object) = .{}, strtab: []const u8 = &[0]u8{}, -// 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. -pub const ARFMAG: *const [2:0]u8 = "`\n"; - -pub const SYM64NAME: *const [7:0]u8 = "/SYM64/"; - -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), "//"); - } - - fn isSymtab(self: ar_hdr) bool { - return mem.eql(u8, getValue(&self.ar_name), "/") or mem.eql(u8, getValue(&self.ar_name), SYM64NAME); - } -}; - 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(Archive.SARMAG) catch return false; + const magic = reader.readBytesNoEof(SARMAG) catch return false; if (!mem.eql(u8, &magic, ARMAG)) return false; return true; } @@ -140,9 +82,267 @@ 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([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0); + return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0); +} + +pub fn setArHdr(opts: struct { + kind: enum { symtab, strtab, object }, + name_off: u32, + size: u32, +}) ar_hdr { + var hdr: ar_hdr = .{ + .ar_name = undefined, + .ar_date = undefined, + .ar_uid = undefined, + .ar_gid = undefined, + .ar_mode = undefined, + .ar_size = undefined, + .ar_fmag = undefined, + }; + @memset(mem.asBytes(&hdr), 0x20); + @memcpy(&hdr.ar_fmag, Archive.ARFMAG); + + { + var stream = std.io.fixedBufferStream(&hdr.ar_name); + const writer = stream.writer(); + switch (opts.kind) { + .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable, + .strtab => writer.print("//", .{}) catch unreachable, + .object => writer.print("/{d}", .{opts.name_off}) catch unreachable, + } + } + { + var stream = std.io.fixedBufferStream(&hdr.ar_size); + stream.writer().print("{d}", .{opts.size}) catch unreachable; + } + + 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 ArSymtab = struct { + symtab: std.ArrayListUnmanaged(Entry) = .{}, + strtab: StringTable = .{}, + + pub fn deinit(ar: *ArSymtab, allocator: Allocator) void { + ar.symtab.deinit(allocator); + ar.strtab.deinit(allocator); + } + + pub fn sort(ar: *ArSymtab) void { + mem.sort(Entry, ar.symtab.items, {}, Entry.lessThan); + } + + pub fn size(ar: ArSymtab, kind: enum { p32, p64 }) usize { + const ptr_size: usize = switch (kind) { + .p32 => 4, + .p64 => 8, + }; + var ss: usize = ptr_size + ar.symtab.items.len * ptr_size; + for (ar.symtab.items) |entry| { + ss += ar.strtab.getAssumeExists(entry.off).len + 1; + } + return ss; + } + + pub fn write(ar: ArSymtab, kind: enum { p32, p64 }, elf_file: *Elf, writer: anytype) !void { + assert(kind == .p64); // TODO p32 + const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar.size(.p64)) }); + try writer.writeAll(mem.asBytes(&hdr)); + + const gpa = elf_file.base.allocator; + var offsets = std.AutoHashMap(File.Index, u64).init(gpa); + defer offsets.deinit(); + try offsets.ensureUnusedCapacity(@intCast(elf_file.objects.items.len + 1)); + + if (elf_file.zigObjectPtr()) |zig_object| { + offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off); + } + + // Number of symbols + try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big); + + // Offsets to files + for (ar.symtab.items) |entry| { + const off = offsets.get(entry.file_index).?; + try writer.writeInt(u64, off, .big); + } + + // Strings + for (ar.symtab.items) |entry| { + try writer.print("{s}\x00", .{ar.strtab.getAssumeExists(entry.off)}); + } + } + + pub fn format( + ar: ArSymtab, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = ar; + _ = unused_fmt_string; + _ = options; + _ = writer; + @compileError("do not format ar symtab directly; use fmt instead"); + } + + const FormatContext = struct { + ar: ArSymtab, + elf_file: *Elf, + }; + + pub fn fmt(ar: ArSymtab, elf_file: *Elf) std.fmt.Formatter(format2) { + return .{ .data = .{ + .ar = ar, + .elf_file = elf_file, + } }; + } + + fn format2( + ctx: FormatContext, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = unused_fmt_string; + _ = options; + const ar = ctx.ar; + const elf_file = ctx.elf_file; + for (ar.symtab.items, 0..) |entry, i| { + const name = ar.strtab.getAssumeExists(entry.off); + const file = elf_file.file(entry.file_index).?; + try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file_index, file.fmtPath() }); + } + } + + const Entry = struct { + /// Offset into the string table. + off: u32, + /// Index of the file defining the global. + file_index: File.Index, + + pub fn lessThan(ctx: void, lhs: Entry, rhs: Entry) bool { + _ = ctx; + if (lhs.off == rhs.off) return lhs.file_index < rhs.file_index; + return lhs.off < rhs.off; + } + }; +}; + +pub const ArStrtab = struct { + buffer: std.ArrayListUnmanaged(u8) = .{}, + + pub fn deinit(ar: *ArStrtab, allocator: Allocator) void { + ar.buffer.deinit(allocator); + } + + pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 { + const off = @as(u32, @intCast(ar.buffer.items.len)); + try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter }); + return off; + } + + pub fn size(ar: ArStrtab) usize { + return ar.buffer.items.len; + } + + pub fn write(ar: ArStrtab, writer: anytype) !void { + const hdr = setArHdr(.{ .kind = .strtab, .name_off = 0, .size = @intCast(ar.size()) }); + try writer.writeAll(mem.asBytes(&hdr)); + try writer.writeAll(ar.buffer.items); + } + + pub fn format( + ar: ArStrtab, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = unused_fmt_string; + _ = options; + try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)}); + } +}; + +pub const ArState = struct { + /// Name offset in the string table. + name_off: u32 = 0, + + /// File offset of the ar_hdr describing the contributing + /// object in the archive. + file_off: u64 = 0, + + /// Total size of the contributing object (excludes ar_hdr). + size: u64 = 0, +}; + const std = @import("std"); const assert = std.debug.assert; const elf = std.elf; @@ -153,4 +353,6 @@ const mem = std.mem; const Allocator = mem.Allocator; const Archive = @This(); const Elf = @import("../Elf.zig"); +const File = @import("file.zig").File; const Object = @import("Object.zig"); +const StringTable = @import("../StringTable.zig"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 12ba88b7a9..bd5ba04834 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -20,6 +20,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{}, num_dynrelocs: u32 = 0, output_symtab_size: Elf.SymtabSize = .{}, +output_ar_state: Archive.ArState = .{}, dwarf: ?Dwarf = null, @@ -502,10 +503,10 @@ 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 { +pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void { const gpa = elf_file.base.allocator; - try elf_file.ar_symtab.ensureUnusedCapacity(gpa, self.globals().len); + try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len); for (self.globals()) |global_index| { const global = elf_file.symbol(global_index); @@ -513,11 +514,45 @@ pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void { 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 = off, .file_index = self.index }); + 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); + 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| { + end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size); + } + self.output_ar_state.size = end_pos; +} + +pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void { + const gpa = elf_file.base.allocator; + const contents = try gpa.alloc(u8, self.output_ar_state.size); + defer gpa.free(contents); + const amt = try elf_file.base.file.?.preadAll(contents, 0); + if (amt != self.output_ar_state.size) return error.InputOutput; + const hdr = Archive.setArHdr(.{ + .kind = .object, + .name_off = self.output_ar_state.name_off, + .size = @intCast(self.output_ar_state.size), + }); + try writer.writeAll(mem.asBytes(&hdr)); + try writer.writeAll(contents); +} + pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void { _ = self; @@ -1533,6 +1568,7 @@ const std = @import("std"); const Air = @import("../../Air.zig"); const Allocator = std.mem.Allocator; +const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); const Dwarf = @import("../Dwarf.zig"); const Elf = @import("../Elf.zig"); diff --git a/src/link/Elf/file.zig b/src/link/Elf/file.zig index 49d097ab61..e31170a178 100644 --- a/src/link/Elf/file.zig +++ b/src/link/Elf/file.zig @@ -196,9 +196,9 @@ pub const File = union(enum) { } } - pub fn updateArSymtab(file: File, elf_file: *Elf) !void { + pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { return switch (file) { - .zig_object => |x| x.updateArSymtab(elf_file), + .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file), .object => @panic("TODO"), inline else => unreachable, }; @@ -219,6 +219,7 @@ const std = @import("std"); const elf = std.elf; const Allocator = std.mem.Allocator; +const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); const Cie = @import("eh_frame.zig").Cie; const Elf = @import("../Elf.zig"); |
