mirror of
https://github.com/ziglang/zig.git
synced 2026-02-04 13:43:46 +00:00
elf: store ar state per input object file
This commit is contained in:
parent
ed2984f335
commit
acd700ac6b
233
src/link/Elf.zig
233
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()});
|
||||
var ar_symtab: Archive.ArSymtab = .{};
|
||||
defer ar_symtab.deinit(gpa);
|
||||
|
||||
if (self.zigObjectPtr()) |zig_object| {
|
||||
try zig_object.updateArSymtab(&ar_symtab, self);
|
||||
}
|
||||
|
||||
ar_symtab.sort();
|
||||
|
||||
// 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_strtab: Archive.ArStrtab = .{};
|
||||
defer ar_strtab.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 });
|
||||
try zig_object.updateArStrtab(gpa, &ar_strtab);
|
||||
zig_object.updateArSize(self);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
// 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();
|
||||
|
||||
// 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;
|
||||
|
||||
// Offsets which we will relocate later.
|
||||
for (0..self.ar_symtab.items.len) |_| {
|
||||
ar_symtab.writer().writeInt(u64, 0, .big) catch unreachable;
|
||||
}
|
||||
|
||||
// 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});
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
assert(mem.isAligned(ar_symtab.items.len, 8));
|
||||
|
||||
// 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));
|
||||
|
||||
files_ptr[2] = end_pos;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 pos: usize = Archive.SARMAG;
|
||||
|
||||
// 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 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;
|
||||
}
|
||||
|
||||
// Zig object if defined
|
||||
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];
|
||||
}
|
||||
|
||||
// TODO parsed positionals
|
||||
|
||||
// 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,
|
||||
break :blk pos;
|
||||
};
|
||||
@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;
|
||||
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});
|
||||
}
|
||||
|
||||
return hdr;
|
||||
var buffer = std.ArrayList(u8).init(gpa);
|
||||
defer buffer.deinit();
|
||||
try buffer.ensureTotalCapacityPrecise(total_size);
|
||||
|
||||
// Write magic
|
||||
try buffer.writer().writeAll(Archive.ARMAG);
|
||||
|
||||
// Write symtab
|
||||
try ar_symtab.write(.p64, self, buffer.writer());
|
||||
if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
|
||||
|
||||
// Write strtab
|
||||
try ar_strtab.write(buffer.writer());
|
||||
if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
|
||||
|
||||
// Write object files
|
||||
if (self.zigObjectPtr()) |zig_object| {
|
||||
try zig_object.writeAr(self, buffer.writer());
|
||||
}
|
||||
|
||||
assert(buffer.items.len == total_size);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user