diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-06 21:17:06 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-11-06 21:18:26 +0100 |
| commit | 261db02018c71e8977d2bf2a78d495cc31abd1bc (patch) | |
| tree | e4de8e92879ff268352fc342ddf0ff23646cb953 /src | |
| parent | 6490e2ed82ebcf7ffe9732bbd7ef881412363336 (diff) | |
| download | zig-261db02018c71e8977d2bf2a78d495cc31abd1bc.tar.gz zig-261db02018c71e8977d2bf2a78d495cc31abd1bc.zip | |
CheckObject: support parsing and dumping archive symtab for ELF
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf.zig | 10 | ||||
| -rw-r--r-- | src/link/Elf/Archive.zig | 109 |
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 = .{}, |
