authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-03 23:08:48+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-04 09:13:18+01:00
logacd700ac6b4ec03412e2bac6aaf168f80f83f521
tree15c00fc6dfb8d7cd3fd9e7d2f53f460877ca6067
parented2984f335bfaf7cc3cb7841554f4cbb958476dd

elf: store ar state per input object file


4 files changed, 347 insertions(+), 243 deletions(-)

src/link/Elf.zig+42-177
......@@ -186,12 +186,6 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}
186186/// such as `resolver` and `comdat_groups_table`.
187187strings: StringTable = .{},
188188
189/// Static archive state.
190/// TODO it may be wise to move it somewhere else, but for the time being, it
191/// is far easier to pollute global state.
192ar_symtab: std.ArrayListUnmanaged(ArSymtabEntry) = .{},
193ar_strtab: StringTable = .{},
194
195189/// When allocating, the ideal_capacity is calculated by
196190/// actual_capacity + (actual_capacity / ideal_factor)
197191const ideal_factor = 3;
......@@ -398,9 +392,6 @@ pub fn deinit(self: *Elf) void {
398392 self.copy_rel.deinit(gpa);
399393 self.rela_dyn.deinit(gpa);
400394 self.rela_plt.deinit(gpa);
401
402 self.ar_symtab.deinit(gpa);
403 self.ar_strtab.deinit(gpa);
404395}
405396
406397pub 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
15531544 try self.writeSymtab();
15541545 try self.writeShStrtab();
15551546 try self.writeElfHeader();
1556
1557 // Update ar symbol table.
1558 try zig_object.asFile().updateArSymtab(self);
15591547 }
15601548
15611549 // TODO parse positionals that we want to make part of the archive
15621550
1563 mem.sort(ArSymtabEntry, self.ar_symtab.items, {}, ArSymtabEntry.lessThan);
1551 // TODO update ar symtab from parsed positionals
15641552
1565 if (build_options.enable_logging) {
1566 state_log.debug("{}", .{self.dumpState()});
1567 }
1568
1569 // Save object paths in filenames strtab.
1570 var ar_strtab = std.ArrayList(u8).init(gpa);
1571 defer ar_strtab.deinit();
1572
1573 var files = std.AutoHashMap(File.Index, struct { u32, u64, u64 }).init(gpa);
1574 defer files.deinit();
1575 try files.ensureUnusedCapacity(@intCast(self.objects.items.len + 1));
1553 var ar_symtab: Archive.ArSymtab = .{};
1554 defer ar_symtab.deinit(gpa);
15761555
15771556 if (self.zigObjectPtr()) |zig_object| {
1578 const off = @as(u32, @intCast(ar_strtab.items.len));
1579 try ar_strtab.writer().print("{s}/\n", .{zig_object.path});
1580 files.putAssumeCapacityNoClobber(zig_object.index, .{ off, 0, 0 });
1581 }
1582
1583 // Align to even byte boundary
1584 {
1585 const end = ar_strtab.items.len;
1586 const aligned = mem.alignForward(usize, end, 2);
1587 try ar_strtab.writer().writeByteNTimes(0, aligned - end);
1557 try zig_object.updateArSymtab(&ar_symtab, self);
15881558 }
15891559
1590 // Encode ar symtab in 64bit format.
1591 var ar_symtab = std.ArrayList(u8).init(gpa);
1592 defer ar_symtab.deinit();
1593 try ar_symtab.ensureUnusedCapacity(8 * (self.ar_symtab.items.len + 1));
1594
1595 // Number of symbols
1596 ar_symtab.writer().writeInt(u64, @as(u64, @intCast(self.ar_symtab.items.len)), .big) catch unreachable;
1560 ar_symtab.sort();
15971561
1598 // Offsets which we will relocate later.
1599 for (0..self.ar_symtab.items.len) |_| {
1600 ar_symtab.writer().writeInt(u64, 0, .big) catch unreachable;
1601 }
1562 // Save object paths in filenames strtab.
1563 var ar_strtab: Archive.ArStrtab = .{};
1564 defer ar_strtab.deinit(gpa);
16021565
1603 // ASCII offsets into the strtab.
1604 for (self.ar_symtab.items) |entry| {
1605 const name = self.ar_strtab.getAssumeExists(entry.off);
1606 try ar_symtab.writer().print("{s}\x00", .{name});
1566 if (self.zigObjectPtr()) |zig_object| {
1567 try zig_object.updateArStrtab(gpa, &ar_strtab);
1568 zig_object.updateArSize(self);
16071569 }
16081570
1609 // Align to 8 bytes if required
1610 {
1611 const end = ar_symtab.items.len;
1612 const aligned = mem.alignForward(usize, end, 8);
1613 try ar_symtab.writer().writeByteNTimes(0, aligned - end);
1614 }
1571 // Update file offsets of contributing objects.
1572 const total_size: u64 = blk: {
1573 var pos: u64 = Archive.SARMAG;
1574 pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64);
1575 pos = mem.alignForward(u64, pos, 2);
1576 pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size();
16151577
1616 assert(mem.isAligned(ar_symtab.items.len, 8));
1578 if (self.zigObjectPtr()) |zig_object| {
1579 pos = mem.alignForward(u64, pos, 2);
1580 zig_object.output_ar_state.file_off = pos;
1581 pos += @sizeOf(Archive.ar_hdr) + zig_object.output_ar_state.size;
1582 }
16171583
1618 // Calculate required size for headers before ZigObject pos in file.
1619 if (self.zigObjectPtr()) |zig_object| {
1620 var file_off: u64 = 0;
1621 // Magic
1622 file_off += Archive.SARMAG;
1623 // Symtab
1624 file_off += @sizeOf(Archive.ar_hdr) + @as(u64, @intCast(ar_symtab.items.len));
1625 // Strtab
1626 file_off += @sizeOf(Archive.ar_hdr) + @as(u64, @intCast(ar_strtab.items.len));
1627
1628 const files_ptr = files.getPtr(zig_object.index).?;
1629 files_ptr[1] = file_off;
1630
1631 // Move ZigObject into place.
1632 {
1633 var end_pos: u64 = self.shdr_table_offset.?;
1634 for (self.shdrs.items) |shdr| {
1635 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
1636 }
1637 const contents = try gpa.alloc(u8, end_pos);
1638 defer gpa.free(contents);
1639 const amt = try self.base.file.?.preadAll(contents, 0);
1640 if (amt != end_pos) return error.InputOutput;
1641 try self.base.file.?.pwriteAll(contents, file_off + @sizeOf(Archive.ar_hdr));
1584 break :blk pos;
1585 };
16421586
1643 files_ptr[2] = end_pos;
1644 }
1587 if (build_options.enable_logging) {
1588 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
1589 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
16451590 }
16461591
1647 // Fixup file offsets in the symtab.
1648 for (self.ar_symtab.items, 1..) |entry, i| {
1649 const file_off = files.get(entry.file_index).?[1];
1650 mem.writeInt(u64, ar_symtab.items[8 * i ..][0..8], file_off, .big);
1651 }
1592 var buffer = std.ArrayList(u8).init(gpa);
1593 defer buffer.deinit();
1594 try buffer.ensureTotalCapacityPrecise(total_size);
16521595
1653 var pos: usize = Archive.SARMAG;
1596 // Write magic
1597 try buffer.writer().writeAll(Archive.ARMAG);
16541598
1655 // Write symtab.
1656 {
1657 const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar_symtab.items.len) });
1658 try self.base.file.?.pwriteAll(mem.asBytes(&hdr), pos);
1659 pos += @sizeOf(Archive.ar_hdr);
1660 try self.base.file.?.pwriteAll(ar_symtab.items, pos);
1661 pos += ar_symtab.items.len;
1662 }
1599 // Write symtab
1600 try ar_symtab.write(.p64, self, buffer.writer());
1601 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
16631602
1664 // Write strtab.
1665 {
1666 const hdr = setArHdr(.{
1667 .kind = .strtab,
1668 .name_off = 0,
1669 .size = @intCast(ar_strtab.items.len),
1670 });
1671 try self.base.file.?.pwriteAll(mem.asBytes(&hdr), pos);
1672 pos += @sizeOf(Archive.ar_hdr);
1673 try self.base.file.?.pwriteAll(ar_strtab.items, pos);
1674 pos += ar_strtab.items.len;
1675 }
1603 // Write strtab
1604 try ar_strtab.write(buffer.writer());
1605 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
16761606
1677 // Zig object if defined
1607 // Write object files
16781608 if (self.zigObjectPtr()) |zig_object| {
1679 const entry = files.get(zig_object.index).?;
1680 const hdr = setArHdr(.{ .kind = .object, .name_off = entry[0], .size = @intCast(entry[2]) });
1681 try self.base.file.?.pwriteAll(mem.asBytes(&hdr), entry[1]);
1682 pos += @sizeOf(Archive.ar_hdr) + entry[2];
1609 try zig_object.writeAr(self, buffer.writer());
16831610 }
16841611
1685 // TODO parsed positionals
1612 assert(buffer.items.len == total_size);
16861613
1687 // Magic bytes.
1688 {
1689 try self.base.file.?.pwriteAll(Archive.ARMAG, 0);
1690 }
1691}
1692
1693fn setArHdr(opts: struct {
1694 kind: enum { symtab, strtab, object },
1695 name_off: u32,
1696 size: u32,
1697}) Archive.ar_hdr {
1698 var hdr: Archive.ar_hdr = .{
1699 .ar_name = undefined,
1700 .ar_date = undefined,
1701 .ar_uid = undefined,
1702 .ar_gid = undefined,
1703 .ar_mode = undefined,
1704 .ar_size = undefined,
1705 .ar_fmag = undefined,
1706 };
1707 @memset(mem.asBytes(&hdr), 0x20);
1708 @memcpy(&hdr.ar_fmag, Archive.ARFMAG);
1709
1710 {
1711 var stream = std.io.fixedBufferStream(&hdr.ar_name);
1712 const writer = stream.writer();
1713 switch (opts.kind) {
1714 .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable,
1715 .strtab => writer.print("//", .{}) catch unreachable,
1716 .object => writer.print("/{d}", .{opts.name_off}) catch unreachable,
1717 }
1718 }
1719 {
1720 var stream = std.io.fixedBufferStream(&hdr.ar_size);
1721 stream.writer().print("{d}", .{opts.size}) catch unreachable;
1722 }
1723
1724 return hdr;
1614 try self.base.file.?.pwriteAll(buffer.items, 0);
17251615}
17261616
17271617pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {
......@@ -5822,18 +5712,6 @@ fn fmtDumpState(
58225712 try writer.print("{}\n", .{self.got.fmt(self)});
58235713 try writer.print("{}\n", .{self.zig_got.fmt(self)});
58245714
5825 if (self.isStaticLib()) {
5826 try writer.writeAll("ar symtab\n");
5827 for (self.ar_symtab.items, 0..) |entry, i| {
5828 try writer.print(" {d} : {s} in file({d})\n", .{
5829 i,
5830 self.ar_strtab.getAssumeExists(entry.off),
5831 entry.file_index,
5832 });
5833 }
5834 try writer.writeByte('\n');
5835 }
5836
58375715 try writer.writeAll("Output shdrs\n");
58385716 for (self.shdrs.items, 0..) |shdr, shndx| {
58395717 try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{
......@@ -5966,19 +5844,6 @@ const LastAtomAndFreeList = struct {
59665844
59675845const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
59685846
5969const ArSymtabEntry = struct {
5970 off: u32,
5971 file_index: File.Index,
5972
5973 pub fn lessThan(ctx: void, lhs: ArSymtabEntry, rhs: ArSymtabEntry) bool {
5974 _ = ctx;
5975 if (lhs.off == rhs.off) {
5976 return lhs.file_index < rhs.file_index;
5977 }
5978 return lhs.off < rhs.off;
5979 }
5980};
5981
59825847pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
59835848pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
59845849
src/link/Elf/Archive.zig+262-60
......@@ -4,69 +4,11 @@ data: []const u8,
44objects: std.ArrayListUnmanaged(Object) = .{},
55strtab: []const u8 = &[0]u8{},
66
7// Archive files start with the ARMAG identifying string. Then follows a
8// `struct ar_hdr', and as many bytes of member file data as its `ar_size'
9// member indicates, for each member file.
10/// String that begins an archive file.
11pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";
12/// Size of that string.
13pub const SARMAG = 8;
14
15/// String in ar_fmag at the end of each header.
16pub const ARFMAG: *const [2:0]u8 = "`\n";
17
18pub const SYM64NAME: *const [7:0]u8 = "/SYM64/";
19
20pub const ar_hdr = extern struct {
21 /// Member file name, sometimes / terminated.
22 ar_name: [16]u8,
23
24 /// File date, decimal seconds since Epoch.
25 ar_date: [12]u8,
26
27 /// User ID, in ASCII format.
28 ar_uid: [6]u8,
29
30 /// Group ID, in ASCII format.
31 ar_gid: [6]u8,
32
33 /// File mode, in ASCII octal.
34 ar_mode: [8]u8,
35
36 /// File size, in ASCII decimal.
37 ar_size: [10]u8,
38
39 /// Always contains ARFMAG.
40 ar_fmag: [2]u8,
41
42 fn date(self: ar_hdr) !u64 {
43 const value = getValue(&self.ar_date);
44 return std.fmt.parseInt(u64, value, 10);
45 }
46
47 fn size(self: ar_hdr) !u32 {
48 const value = getValue(&self.ar_size);
49 return std.fmt.parseInt(u32, value, 10);
50 }
51
52 fn getValue(raw: []const u8) []const u8 {
53 return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)});
54 }
55
56 fn isStrtab(self: ar_hdr) bool {
57 return mem.eql(u8, getValue(&self.ar_name), "//");
58 }
59
60 fn isSymtab(self: ar_hdr) bool {
61 return mem.eql(u8, getValue(&self.ar_name), "/") or mem.eql(u8, getValue(&self.ar_name), SYM64NAME);
62 }
63};
64
657pub fn isArchive(path: []const u8) !bool {
668 const file = try std.fs.cwd().openFile(path, .{});
679 defer file.close();
6810 const reader = file.reader();
69 const magic = reader.readBytesNoEof(Archive.SARMAG) catch return false;
11 const magic = reader.readBytesNoEof(SARMAG) catch return false;
7012 if (!mem.eql(u8, &magic, ARMAG)) return false;
7113 return true;
7214}
......@@ -140,9 +82,267 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {
14082
14183fn getString(self: Archive, off: u32) []const u8 {
14284 assert(off < self.strtab.len);
143 return mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0);
85 return mem.sliceTo(@as([*:strtab_delimiter]const u8, @ptrCast(self.strtab.ptr + off)), 0);
86}
87
88pub fn setArHdr(opts: struct {
89 kind: enum { symtab, strtab, object },
90 name_off: u32,
91 size: u32,
92}) ar_hdr {
93 var hdr: ar_hdr = .{
94 .ar_name = undefined,
95 .ar_date = undefined,
96 .ar_uid = undefined,
97 .ar_gid = undefined,
98 .ar_mode = undefined,
99 .ar_size = undefined,
100 .ar_fmag = undefined,
101 };
102 @memset(mem.asBytes(&hdr), 0x20);
103 @memcpy(&hdr.ar_fmag, Archive.ARFMAG);
104
105 {
106 var stream = std.io.fixedBufferStream(&hdr.ar_name);
107 const writer = stream.writer();
108 switch (opts.kind) {
109 .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable,
110 .strtab => writer.print("//", .{}) catch unreachable,
111 .object => writer.print("/{d}", .{opts.name_off}) catch unreachable,
112 }
113 }
114 {
115 var stream = std.io.fixedBufferStream(&hdr.ar_size);
116 stream.writer().print("{d}", .{opts.size}) catch unreachable;
117 }
118
119 return hdr;
144120}
145121
122// Archive files start with the ARMAG identifying string. Then follows a
123// `struct ar_hdr', and as many bytes of member file data as its `ar_size'
124// member indicates, for each member file.
125/// String that begins an archive file.
126pub const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";
127/// Size of that string.
128pub const SARMAG = 8;
129
130/// String in ar_fmag at the end of each header.
131const ARFMAG: *const [2:0]u8 = "`\n";
132
133/// Strtab identifier
134const STRNAME: *const [2:0]u8 = "//";
135
136/// 32-bit symtab identifier
137const SYMNAME: *const [1:0]u8 = "/";
138
139/// 64-bit symtab identifier
140const SYM64NAME: *const [7:0]u8 = "/SYM64/";
141
142const strtab_delimiter = '\n';
143
144pub const ar_hdr = extern struct {
145 /// Member file name, sometimes / terminated.
146 ar_name: [16]u8,
147
148 /// File date, decimal seconds since Epoch.
149 ar_date: [12]u8,
150
151 /// User ID, in ASCII format.
152 ar_uid: [6]u8,
153
154 /// Group ID, in ASCII format.
155 ar_gid: [6]u8,
156
157 /// File mode, in ASCII octal.
158 ar_mode: [8]u8,
159
160 /// File size, in ASCII decimal.
161 ar_size: [10]u8,
162
163 /// Always contains ARFMAG.
164 ar_fmag: [2]u8,
165
166 fn date(self: ar_hdr) !u64 {
167 const value = getValue(&self.ar_date);
168 return std.fmt.parseInt(u64, value, 10);
169 }
170
171 fn size(self: ar_hdr) !u32 {
172 const value = getValue(&self.ar_size);
173 return std.fmt.parseInt(u32, value, 10);
174 }
175
176 fn getValue(raw: []const u8) []const u8 {
177 return mem.trimRight(u8, raw, &[_]u8{@as(u8, 0x20)});
178 }
179
180 fn isStrtab(self: ar_hdr) bool {
181 return mem.eql(u8, getValue(&self.ar_name), STRNAME);
182 }
183
184 fn isSymtab(self: ar_hdr) bool {
185 return mem.eql(u8, getValue(&self.ar_name), SYMNAME) or mem.eql(u8, getValue(&self.ar_name), SYM64NAME);
186 }
187};
188
189pub const ArSymtab = struct {
190 symtab: std.ArrayListUnmanaged(Entry) = .{},
191 strtab: StringTable = .{},
192
193 pub fn deinit(ar: *ArSymtab, allocator: Allocator) void {
194 ar.symtab.deinit(allocator);
195 ar.strtab.deinit(allocator);
196 }
197
198 pub fn sort(ar: *ArSymtab) void {
199 mem.sort(Entry, ar.symtab.items, {}, Entry.lessThan);
200 }
201
202 pub fn size(ar: ArSymtab, kind: enum { p32, p64 }) usize {
203 const ptr_size: usize = switch (kind) {
204 .p32 => 4,
205 .p64 => 8,
206 };
207 var ss: usize = ptr_size + ar.symtab.items.len * ptr_size;
208 for (ar.symtab.items) |entry| {
209 ss += ar.strtab.getAssumeExists(entry.off).len + 1;
210 }
211 return ss;
212 }
213
214 pub fn write(ar: ArSymtab, kind: enum { p32, p64 }, elf_file: *Elf, writer: anytype) !void {
215 assert(kind == .p64); // TODO p32
216 const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar.size(.p64)) });
217 try writer.writeAll(mem.asBytes(&hdr));
218
219 const gpa = elf_file.base.allocator;
220 var offsets = std.AutoHashMap(File.Index, u64).init(gpa);
221 defer offsets.deinit();
222 try offsets.ensureUnusedCapacity(@intCast(elf_file.objects.items.len + 1));
223
224 if (elf_file.zigObjectPtr()) |zig_object| {
225 offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off);
226 }
227
228 // Number of symbols
229 try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big);
230
231 // Offsets to files
232 for (ar.symtab.items) |entry| {
233 const off = offsets.get(entry.file_index).?;
234 try writer.writeInt(u64, off, .big);
235 }
236
237 // Strings
238 for (ar.symtab.items) |entry| {
239 try writer.print("{s}\x00", .{ar.strtab.getAssumeExists(entry.off)});
240 }
241 }
242
243 pub fn format(
244 ar: ArSymtab,
245 comptime unused_fmt_string: []const u8,
246 options: std.fmt.FormatOptions,
247 writer: anytype,
248 ) !void {
249 _ = ar;
250 _ = unused_fmt_string;
251 _ = options;
252 _ = writer;
253 @compileError("do not format ar symtab directly; use fmt instead");
254 }
255
256 const FormatContext = struct {
257 ar: ArSymtab,
258 elf_file: *Elf,
259 };
260
261 pub fn fmt(ar: ArSymtab, elf_file: *Elf) std.fmt.Formatter(format2) {
262 return .{ .data = .{
263 .ar = ar,
264 .elf_file = elf_file,
265 } };
266 }
267
268 fn format2(
269 ctx: FormatContext,
270 comptime unused_fmt_string: []const u8,
271 options: std.fmt.FormatOptions,
272 writer: anytype,
273 ) !void {
274 _ = unused_fmt_string;
275 _ = options;
276 const ar = ctx.ar;
277 const elf_file = ctx.elf_file;
278 for (ar.symtab.items, 0..) |entry, i| {
279 const name = ar.strtab.getAssumeExists(entry.off);
280 const file = elf_file.file(entry.file_index).?;
281 try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file_index, file.fmtPath() });
282 }
283 }
284
285 const Entry = struct {
286 /// Offset into the string table.
287 off: u32,
288 /// Index of the file defining the global.
289 file_index: File.Index,
290
291 pub fn lessThan(ctx: void, lhs: Entry, rhs: Entry) bool {
292 _ = ctx;
293 if (lhs.off == rhs.off) return lhs.file_index < rhs.file_index;
294 return lhs.off < rhs.off;
295 }
296 };
297};
298
299pub const ArStrtab = struct {
300 buffer: std.ArrayListUnmanaged(u8) = .{},
301
302 pub fn deinit(ar: *ArStrtab, allocator: Allocator) void {
303 ar.buffer.deinit(allocator);
304 }
305
306 pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {
307 const off = @as(u32, @intCast(ar.buffer.items.len));
308 try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter });
309 return off;
310 }
311
312 pub fn size(ar: ArStrtab) usize {
313 return ar.buffer.items.len;
314 }
315
316 pub fn write(ar: ArStrtab, writer: anytype) !void {
317 const hdr = setArHdr(.{ .kind = .strtab, .name_off = 0, .size = @intCast(ar.size()) });
318 try writer.writeAll(mem.asBytes(&hdr));
319 try writer.writeAll(ar.buffer.items);
320 }
321
322 pub fn format(
323 ar: ArStrtab,
324 comptime unused_fmt_string: []const u8,
325 options: std.fmt.FormatOptions,
326 writer: anytype,
327 ) !void {
328 _ = unused_fmt_string;
329 _ = options;
330 try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)});
331 }
332};
333
334pub const ArState = struct {
335 /// Name offset in the string table.
336 name_off: u32 = 0,
337
338 /// File offset of the ar_hdr describing the contributing
339 /// object in the archive.
340 file_off: u64 = 0,
341
342 /// Total size of the contributing object (excludes ar_hdr).
343 size: u64 = 0,
344};
345
146346const std = @import("std");
147347const assert = std.debug.assert;
148348const elf = std.elf;
......@@ -153,4 +353,6 @@ const mem = std.mem;
153353const Allocator = mem.Allocator;
154354const Archive = @This();
155355const Elf = @import("../Elf.zig");
356const File = @import("file.zig").File;
156357const Object = @import("Object.zig");
358const StringTable = @import("../StringTable.zig");
src/link/Elf/ZigObject.zig+40-4
......@@ -20,6 +20,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
2020num_dynrelocs: u32 = 0,
2121
2222output_symtab_size: Elf.SymtabSize = .{},
23output_ar_state: Archive.ArState = .{},
2324
2425dwarf: ?Dwarf = null,
2526
......@@ -502,10 +503,10 @@ fn sortSymbols(self: *ZigObject, elf_file: *Elf) error{OutOfMemory}!void {
502503 // mem.sort(Entry, sorted_globals, elf_file, Entry.lessThan);
503504}
504505
505pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void {
506pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
506507 const gpa = elf_file.base.allocator;
507508
508 try elf_file.ar_symtab.ensureUnusedCapacity(gpa, self.globals().len);
509 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);
509510
510511 for (self.globals()) |global_index| {
511512 const global = elf_file.symbol(global_index);
......@@ -513,11 +514,45 @@ pub fn updateArSymtab(self: ZigObject, elf_file: *Elf) !void {
513514 assert(file_ptr.index() == self.index);
514515 if (global.type(elf_file) == elf.SHN_UNDEF) continue;
515516
516 const off = try elf_file.ar_strtab.insert(gpa, global.name(elf_file));
517 elf_file.ar_symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
517 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
518 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
518519 }
519520}
520521
522pub fn updateArStrtab(
523 self: *ZigObject,
524 allocator: Allocator,
525 ar_strtab: *Archive.ArStrtab,
526) error{OutOfMemory}!void {
527 const name = try std.fmt.allocPrint(allocator, "{s}.o", .{std.fs.path.stem(self.path)});
528 defer allocator.free(name);
529 const name_off = try ar_strtab.insert(allocator, name);
530 self.output_ar_state.name_off = name_off;
531}
532
533pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void {
534 var end_pos: u64 = elf_file.shdr_table_offset.?;
535 for (elf_file.shdrs.items) |shdr| {
536 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
537 }
538 self.output_ar_state.size = end_pos;
539}
540
541pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
542 const gpa = elf_file.base.allocator;
543 const contents = try gpa.alloc(u8, self.output_ar_state.size);
544 defer gpa.free(contents);
545 const amt = try elf_file.base.file.?.preadAll(contents, 0);
546 if (amt != self.output_ar_state.size) return error.InputOutput;
547 const hdr = Archive.setArHdr(.{
548 .kind = .object,
549 .name_off = self.output_ar_state.name_off,
550 .size = @intCast(self.output_ar_state.size),
551 });
552 try writer.writeAll(mem.asBytes(&hdr));
553 try writer.writeAll(contents);
554}
555
521556pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
522557 _ = self;
523558
......@@ -1533,6 +1568,7 @@ const std = @import("std");
15331568
15341569const Air = @import("../../Air.zig");
15351570const Allocator = std.mem.Allocator;
1571const Archive = @import("Archive.zig");
15361572const Atom = @import("Atom.zig");
15371573const Dwarf = @import("../Dwarf.zig");
15381574const Elf = @import("../Elf.zig");
src/link/Elf/file.zig+3-2
......@@ -196,9 +196,9 @@ pub const File = union(enum) {
196196 }
197197 }
198198
199 pub fn updateArSymtab(file: File, elf_file: *Elf) !void {
199 pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
200200 return switch (file) {
201 .zig_object => |x| x.updateArSymtab(elf_file),
201 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),
202202 .object => @panic("TODO"),
203203 inline else => unreachable,
204204 };
......@@ -219,6 +219,7 @@ const std = @import("std");
219219const elf = std.elf;
220220
221221const Allocator = std.mem.Allocator;
222const Archive = @import("Archive.zig");
222223const Atom = @import("Atom.zig");
223224const Cie = @import("eh_frame.zig").Cie;
224225const Elf = @import("../Elf.zig");