aboutsummaryrefslogtreecommitdiff
path: root/lib/std/elf.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-11-07 03:22:14 +0100
committerGitHub <noreply@github.com>2023-11-07 03:22:14 +0100
commitbf0387b6bb9c65c30f14e699a2f2cfbfea27184e (patch)
treec0d68c1f225ed91cc900475958d1c125ae3239fb /lib/std/elf.zig
parent234693bcbba6f55ff6e975ddbedf0fad4dfaa8f1 (diff)
parent261db02018c71e8977d2bf2a78d495cc31abd1bc (diff)
downloadzig-bf0387b6bb9c65c30f14e699a2f2cfbfea27184e.tar.gz
zig-bf0387b6bb9c65c30f14e699a2f2cfbfea27184e.zip
Merge pull request #17873 from ziglang/elf-archive
elf: implement archiving input object files
Diffstat (limited to 'lib/std/elf.zig')
-rw-r--r--lib/std/elf.zig89
1 files changed, 89 insertions, 0 deletions
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 7cb36a17ee..4c53898df8 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -1896,3 +1896,92 @@ pub const STV = enum(u2) {
HIDDEN = 2,
PROTECTED = 3,
};
+
+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,
+
+ pub fn date(self: ar_hdr) std.fmt.ParseIntError!u64 {
+ const value = mem.trimRight(u8, &self.ar_date, &[_]u8{0x20});
+ return std.fmt.parseInt(u64, value, 10);
+ }
+
+ pub fn size(self: ar_hdr) std.fmt.ParseIntError!u32 {
+ const value = mem.trimRight(u8, &self.ar_size, &[_]u8{0x20});
+ return std.fmt.parseInt(u32, value, 10);
+ }
+
+ pub fn isStrtab(self: ar_hdr) bool {
+ return mem.eql(u8, &self.ar_name, STRNAME);
+ }
+
+ pub fn isSymtab(self: ar_hdr) bool {
+ return mem.eql(u8, &self.ar_name, SYMNAME);
+ }
+
+ pub fn isSymtab64(self: ar_hdr) bool {
+ return mem.eql(u8, &self.ar_name, SYM64NAME);
+ }
+
+ pub fn isSymdef(self: ar_hdr) bool {
+ return mem.eql(u8, &self.ar_name, SYMDEFNAME);
+ }
+
+ pub fn isSymdefSorted(self: ar_hdr) bool {
+ return mem.eql(u8, &self.ar_name, SYMDEFSORTEDNAME);
+ }
+
+ pub 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];
+ }
+
+ pub fn nameOffset(self: ar_hdr) std.fmt.ParseIntError!?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);
+ }
+};
+
+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.
+pub const ARFMAG = "`\n";
+/// 32-bit symtab identifier
+pub const SYMNAME = genSpecialMemberName("/");
+/// Strtab identifier
+pub const STRNAME = genSpecialMemberName("//");
+/// 64-bit symtab identifier
+pub const SYM64NAME = genSpecialMemberName("/SYM64/");
+pub const SYMDEFNAME = genSpecialMemberName("__.SYMDEF");
+pub const SYMDEFSORTEDNAME = genSpecialMemberName("__.SYMDEF SORTED");