Commit acd700ac6b
Changed files (4)
src
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");
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");
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");
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;