authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-05 12:08:15+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-05 12:08:15+01:00
log8d7ec05070ba5798adbeaf9a7153b6316fa6dcc3
treeec26ac5cd4ef5e9bdd13b0f426296ed7054f1035
parentf24ceec35a6fd1e5e6a671461b78919b5f588a32

elf: actually save correct object names in the archive


2 files changed, 60 insertions(+), 42 deletions(-)

src/link/Elf.zig+1-1
...@@ -1581,7 +1581,7 @@ pub fn flushStaticLib(...@@ -1581,7 +1581,7 @@ pub fn flushStaticLib(
15811581
1582 // Update file offsets of contributing objects.1582 // Update file offsets of contributing objects.
1583 const total_size: usize = blk: {1583 const total_size: usize = blk: {
1584 var pos: usize = Archive.SARMAG;1584 var pos: usize = Archive.ARMAG.len;
1585 pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64);1585 pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64);
15861586
1587 if (ar_strtab.size() > 0) {1587 if (ar_strtab.size() > 0) {
src/link/Elf/Archive.zig+59-41
...@@ -8,7 +8,7 @@ pub fn isArchive(path: []const u8) !bool {...@@ -8,7 +8,7 @@ pub fn isArchive(path: []const u8) !bool {
8 const file = try std.fs.cwd().openFile(path, .{});8 const file = try std.fs.cwd().openFile(path, .{});
9 defer file.close();9 defer file.close();
10 const reader = file.reader();10 const reader = file.reader();
11 const magic = reader.readBytesNoEof(SARMAG) catch return false;11 const magic = reader.readBytesNoEof(ARMAG.len) catch return false;
12 if (!mem.eql(u8, &magic, ARMAG)) return false;12 if (!mem.eql(u8, &magic, ARMAG)) return false;
13 return true;13 return true;
14}14}
...@@ -24,14 +24,12 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {...@@ -24,14 +24,12 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {
2424
25 var stream = std.io.fixedBufferStream(self.data);25 var stream = std.io.fixedBufferStream(self.data);
26 const reader = stream.reader();26 const reader = stream.reader();
27 _ = try reader.readBytesNoEof(SARMAG);27 _ = try reader.readBytesNoEof(ARMAG.len);
2828
29 while (true) {29 while (true) {
30 if (stream.pos >= self.data.len) break;30 if (stream.pos >= self.data.len) break;
31 if (!mem.isAligned(stream.pos, 2)) stream.pos += 1;
3132
32 if (stream.pos % 2 != 0) {
33 stream.pos += 1;
34 }
35 const hdr = try reader.readStruct(ar_hdr);33 const hdr = try reader.readStruct(ar_hdr);
3634
37 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {35 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
...@@ -48,28 +46,23 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {...@@ -48,28 +46,23 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {
48 _ = stream.seekBy(size) catch {};46 _ = stream.seekBy(size) catch {};
49 }47 }
5048
51 if (hdr.isSymtab()) continue;49 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
52 if (hdr.isStrtab()) {50 if (hdr.isStrtab()) {
53 self.strtab = self.data[stream.pos..][0..size];51 self.strtab = self.data[stream.pos..][0..size];
54 continue;52 continue;
55 }53 }
54 if (hdr.isSymdef() or hdr.isSymdefSorted()) continue;
5655
57 const name = ar_hdr.getValue(&hdr.ar_name);56 const name = if (hdr.name()) |name|
5857 try gpa.dupe(u8, name)
59 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;58 else if (try hdr.nameOffset()) |off|
6059 try gpa.dupe(u8, self.getString(off))
61 const object_name = blk: {60 else
62 if (name[0] == '/') {61 unreachable;
63 const off = try std.fmt.parseInt(u32, name[1..], 10);
64 const object_name = self.getString(off);
65 break :blk try gpa.dupe(u8, object_name[0 .. object_name.len - 1]); // To account for trailing '/'
66 }
67 break :blk try gpa.dupe(u8, name);
68 };
6962
70 const object = Object{63 const object = Object{
71 .archive = try gpa.dupe(u8, self.path),64 .archive = try gpa.dupe(u8, self.path),
72 .path = object_name,65 .path = name,
73 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),66 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
74 .index = undefined,67 .index = undefined,
75 .alive = false,68 .alive = false,
...@@ -83,7 +76,8 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {...@@ -83,7 +76,8 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {
8376
84fn getString(self: Archive, off: u32) []const u8 {77fn getString(self: Archive, off: u32) []const u8 {
85 assert(off < self.strtab.len);78 assert(off < self.strtab.len);
86 return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0);79 const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0);
80 return name[0 .. name.len - 1];
87}81}
8882
89pub fn setArHdr(opts: struct {83pub fn setArHdr(opts: struct {
...@@ -113,7 +107,7 @@ pub fn setArHdr(opts: struct {...@@ -113,7 +107,7 @@ pub fn setArHdr(opts: struct {
113 switch (opts.name) {107 switch (opts.name) {
114 .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable,108 .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable,
115 .strtab => writer.print("//", .{}) catch unreachable,109 .strtab => writer.print("//", .{}) catch unreachable,
116 .name => |x| writer.print("{s}", .{x}) catch unreachable,110 .name => |x| writer.print("{s}/", .{x}) catch unreachable,
117 .name_off => |x| writer.print("/{d}", .{x}) catch unreachable,111 .name_off => |x| writer.print("/{d}", .{x}) catch unreachable,
118 }112 }
119 }113 }
...@@ -125,25 +119,27 @@ pub fn setArHdr(opts: struct {...@@ -125,25 +119,27 @@ pub fn setArHdr(opts: struct {
125 return hdr;119 return hdr;
126}120}
127121
122fn genSpecialMemberName(comptime name: []const u8) *const [16]u8 {
123 assert(name.len <= 16);
124 const padding = 16 - name.len;
125 return name ++ &[_]u8{0x20} ** padding;
126}
127
128// Archive files start with the ARMAG identifying string. Then follows a128// Archive files start with the ARMAG identifying string. Then follows a
129// `struct ar_hdr', and as many bytes of member file data as its `ar_size'129// `struct ar_hdr', and as many bytes of member file data as its `ar_size'
130// member indicates, for each member file.130// member indicates, for each member file.
131/// String that begins an archive file.131/// String that begins an archive file.
132pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";132pub const ARMAG = "!<arch>\n";
133/// Size of that string.
134pub const SARMAG = 8;
135
136/// String in ar_fmag at the end of each header.133/// String in ar_fmag at the end of each header.
137const ARFMAG: *const [2:0]u8 = "`\n";134const ARFMAG = "`\n";
138
139/// Strtab identifier
140const STRNAME: *const [2:0]u8 = "//";
141
142/// 32-bit symtab identifier135/// 32-bit symtab identifier
143const SYMNAME: *const [1:0]u8 = "/";136const SYMNAME = genSpecialMemberName("/");
144137/// Strtab identifier
138const STRNAME = genSpecialMemberName("//");
145/// 64-bit symtab identifier139/// 64-bit symtab identifier
146const SYM64NAME: *const [7:0]u8 = "/SYM64/";140const SYM64NAME = genSpecialMemberName("/SYM64/");
141const SYMDEFNAME = genSpecialMemberName("__.SYMDEF");
142const SYMDEFSORTEDNAME = genSpecialMemberName("__.SYMDEF SORTED");
147143
148const strtab_delimiter = '\n';144const strtab_delimiter = '\n';
149145
...@@ -170,25 +166,47 @@ pub const ar_hdr = extern struct {...@@ -170,25 +166,47 @@ pub const ar_hdr = extern struct {
170 ar_fmag: [2]u8,166 ar_fmag: [2]u8,
171167
172 fn date(self: ar_hdr) !u64 {168 fn date(self: ar_hdr) !u64 {
173 const value = getValue(&self.ar_date);169 const value = mem.trimRight(u8, &self.ar_date, &[_]u8{0x20});
174 return std.fmt.parseInt(u64, value, 10);170 return std.fmt.parseInt(u64, value, 10);
175 }171 }
176172
177 fn size(self: ar_hdr) !u32 {173 fn size(self: ar_hdr) !u32 {
178 const value = getValue(&self.ar_size);174 const value = mem.trimRight(u8, &self.ar_size, &[_]u8{0x20});
179 return std.fmt.parseInt(u32, value, 10);175 return std.fmt.parseInt(u32, value, 10);
180 }176 }
181177
182 fn getValue(raw: []const u8) []const u8 {
183 return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)});
184 }
185
186 fn isStrtab(self: ar_hdr) bool {178 fn isStrtab(self: ar_hdr) bool {
187 return mem.eql(u8, getValue(&self.ar_name), STRNAME);179 return mem.eql(u8, &self.ar_name, STRNAME);
188 }180 }
189181
190 fn isSymtab(self: ar_hdr) bool {182 fn isSymtab(self: ar_hdr) bool {
191 return mem.eql(u8, getValue(&self.ar_name), SYMNAME) or mem.eql(u8, getValue(&self.ar_name), SYM64NAME);183 return mem.eql(u8, &self.ar_name, SYMNAME);
184 }
185
186 fn isSymtab64(self: ar_hdr) bool {
187 return mem.eql(u8, &self.ar_name, SYM64NAME);
188 }
189
190 fn isSymdef(self: ar_hdr) bool {
191 return mem.eql(u8, &self.ar_name, SYMDEFNAME);
192 }
193
194 fn isSymdefSorted(self: ar_hdr) bool {
195 return mem.eql(u8, &self.ar_name, SYMDEFSORTEDNAME);
196 }
197
198 fn name(self: *const ar_hdr) ?[]const u8 {
199 const value = &self.ar_name;
200 if (value[0] == '/') return null;
201 const sentinel = mem.indexOfScalar(u8, value, '/') orelse value.len;
202 return value[0..sentinel];
203 }
204
205 fn nameOffset(self: ar_hdr) !?u32 {
206 const value = &self.ar_name;
207 if (value[0] != '/') return null;
208 const trimmed = mem.trimRight(u8, value, &[_]u8{0x20});
209 return try std.fmt.parseInt(u32, trimmed[1..], 10);
192 }210 }
193};211};
194212