aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-11-06 21:17:06 +0100
committerJakub Konka <kubkon@jakubkonka.com>2023-11-06 21:18:26 +0100
commit261db02018c71e8977d2bf2a78d495cc31abd1bc (patch)
treee4de8e92879ff268352fc342ddf0ff23646cb953 /src/link
parent6490e2ed82ebcf7ffe9732bbd7ef881412363336 (diff)
downloadzig-261db02018c71e8977d2bf2a78d495cc31abd1bc.tar.gz
zig-261db02018c71e8977d2bf2a78d495cc31abd1bc.zip
CheckObject: support parsing and dumping archive symtab for ELF
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Elf.zig10
-rw-r--r--src/link/Elf/Archive.zig109
2 files changed, 15 insertions, 104 deletions
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index adeeb0bbbb..0281fb223e 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1582,12 +1582,12 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
// Update file offsets of contributing objects.
const total_size: usize = blk: {
- var pos: usize = Archive.ARMAG.len;
- 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();
}
for (files.items) |index| {
@@ -1599,7 +1599,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
};
pos = mem.alignForward(usize, pos, 2);
state.file_off = pos;
- pos += @sizeOf(Archive.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
+ pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
}
break :blk pos;
@@ -1615,7 +1615,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
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());
diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig
index ee35f0fece..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(ARMAG.len) 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,19 +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(ARMAG.len);
+ _ = try reader.readBytesNoEof(elf.ARMAG.len);
while (true) {
if (stream.pos >= self.data.len) break;
if (!mem.isAligned(stream.pos, 2)) 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;
}
@@ -88,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,
@@ -99,13 +99,13 @@ 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_off => |x| writer.print("/{d}", .{x}) catch unreachable,
@@ -119,98 +119,9 @@ pub fn setArHdr(opts: struct {
return hdr;
}
-fn genSpecialMemberName(comptime name: []const u8) *const [16]u8 {
- assert(name.len <= 16);
- const padding = 16 - name.len;
- return name ++ &[_]u8{0x20} ** padding;
-}
-
-// 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 = "!<arch>\n";
-/// String in ar_fmag at the end of each header.
-const ARFMAG = "`\n";
-/// 32-bit symtab identifier
-const SYMNAME = genSpecialMemberName("/");
-/// Strtab identifier
-const STRNAME = genSpecialMemberName("//");
-/// 64-bit symtab identifier
-const SYM64NAME = genSpecialMemberName("/SYM64/");
-const SYMDEFNAME = genSpecialMemberName("__.SYMDEF");
-const SYMDEFSORTEDNAME = genSpecialMemberName("__.SYMDEF SORTED");
-
const strtab_delimiter = '\n';
pub const max_member_name_len = 15;
-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 = mem.trimRight(u8, &self.ar_date, &[_]u8{0x20});
- return std.fmt.parseInt(u64, value, 10);
- }
-
- fn size(self: ar_hdr) !u32 {
- const value = mem.trimRight(u8, &self.ar_size, &[_]u8{0x20});
- return std.fmt.parseInt(u32, value, 10);
- }
-
- fn isStrtab(self: ar_hdr) bool {
- return mem.eql(u8, &self.ar_name, STRNAME);
- }
-
- fn isSymtab(self: ar_hdr) bool {
- return mem.eql(u8, &self.ar_name, SYMNAME);
- }
-
- fn isSymtab64(self: ar_hdr) bool {
- return mem.eql(u8, &self.ar_name, SYM64NAME);
- }
-
- fn isSymdef(self: ar_hdr) bool {
- return mem.eql(u8, &self.ar_name, SYMDEFNAME);
- }
-
- fn isSymdefSorted(self: ar_hdr) bool {
- return mem.eql(u8, &self.ar_name, SYMDEFSORTEDNAME);
- }
-
- fn name(self: *const ar_hdr) ?[]const u8 {
- const value = &self.ar_name;
- if (value[0] == '/') return null;
- const sentinel = mem.indexOfScalar(u8, value, '/') orelse value.len;
- return value[0..sentinel];
- }
-
- fn nameOffset(self: ar_hdr) !?u32 {
- const value = &self.ar_name;
- if (value[0] != '/') return null;
- const trimmed = mem.trimRight(u8, value, &[_]u8{0x20});
- return try std.fmt.parseInt(u32, trimmed[1..], 10);
- }
-};
-
pub const ArSymtab = struct {
symtab: std.ArrayListUnmanaged(Entry) = .{},
strtab: StringTable = .{},