authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-05 13:37:13+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-05 13:37:13+01:00
log8142925c7e5cb6ec21ca7046b37140a735735b51
treea63d8afa243a16248b85266e80f19ab0d09a3872
parent55fa8a04f1853deb473339cdc610cbf012ae0d61

elf: hook up saving object files in an archive


5 files changed, 61 insertions(+), 27 deletions(-)

src/link/Elf.zig+6-1
...@@ -288,7 +288,9 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -288,7 +288,9 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
288 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));288 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
289 self.files.set(index, .{ .zig_object = .{289 self.files.set(index, .{ .zig_object = .{
290 .index = index,290 .index = index,
291 .path = options.module.?.main_mod.root_src_path,291 .path = try std.fmt.allocPrint(self.base.allocator, "{s}.o", .{std.fs.path.stem(
292 options.module.?.main_mod.root_src_path,
293 )}),
292 } });294 } });
293 self.zig_object_index = index;295 self.zig_object_index = index;
294 try self.zigObjectPtr().?.init(self);296 try self.zigObjectPtr().?.init(self);
...@@ -1553,6 +1555,9 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void...@@ -1553,6 +1555,9 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
1553 var files = std.ArrayList(File.Index).init(gpa);1555 var files = std.ArrayList(File.Index).init(gpa);
1554 defer files.deinit();1556 defer files.deinit();
1555 try files.ensureTotalCapacityPrecise(self.objects.items.len + 1);1557 try files.ensureTotalCapacityPrecise(self.objects.items.len + 1);
1558 // Note to self: we currently must have ZigObject written out first as we write the object
1559 // file into the same file descriptor and then re-read its contents.
1560 // TODO implement writing ZigObject to a buffer instead of file.
1556 if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index);1561 if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index);
1557 for (self.objects.items) |index| files.appendAssumeCapacity(index);1562 for (self.objects.items) |index| files.appendAssumeCapacity(index);
15581563
src/link/Elf/Archive.zig+4
...@@ -142,6 +142,7 @@ const SYMDEFNAME = genSpecialMemberName("__.SYMDEF");...@@ -142,6 +142,7 @@ const SYMDEFNAME = genSpecialMemberName("__.SYMDEF");
142const SYMDEFSORTEDNAME = genSpecialMemberName("__.SYMDEF SORTED");142const SYMDEFSORTEDNAME = genSpecialMemberName("__.SYMDEF SORTED");
143143
144const strtab_delimiter = '\n';144const strtab_delimiter = '\n';
145pub const max_member_name_len = 15;
145146
146pub const ar_hdr = extern struct {147pub const ar_hdr = extern struct {
147 /// Member file name, sometimes / terminated.148 /// Member file name, sometimes / terminated.
...@@ -248,6 +249,9 @@ pub const ArSymtab = struct {...@@ -248,6 +249,9 @@ pub const ArSymtab = struct {
248 if (elf_file.zigObjectPtr()) |zig_object| {249 if (elf_file.zigObjectPtr()) |zig_object| {
249 offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off);250 offsets.putAssumeCapacityNoClobber(zig_object.index, zig_object.output_ar_state.file_off);
250 }251 }
252 for (elf_file.objects.items) |index| {
253 offsets.putAssumeCapacityNoClobber(index, elf_file.file(index).?.object.output_ar_state.file_off);
254 }
251255
252 // Number of symbols256 // Number of symbols
253 try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big);257 try writer.writeInt(u64, @as(u64, @intCast(ar.symtab.items.len)), .big);
src/link/Elf/Object.zig+30
...@@ -654,6 +654,36 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {...@@ -654,6 +654,36 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
654 }654 }
655}655}
656656
657pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
658 const gpa = elf_file.base.allocator;
659 const start = self.first_global orelse self.symtab.items.len;
660
661 try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.symtab.items.len - start);
662
663 for (self.symtab.items[start..]) |sym| {
664 if (sym.st_shndx == elf.SHN_UNDEF) continue;
665 const off = try ar_symtab.strtab.insert(gpa, self.getString(sym.st_name));
666 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
667 }
668}
669
670pub fn updateArSize(self: *Object) void {
671 self.output_ar_state.size = self.data.len;
672}
673
674pub fn writeAr(self: Object, writer: anytype) !void {
675 const name = self.path;
676 const hdr = Archive.setArHdr(.{
677 .name = if (name.len <= Archive.max_member_name_len)
678 .{ .name = name }
679 else
680 .{ .name_off = self.output_ar_state.name_off },
681 .size = @intCast(self.data.len),
682 });
683 try writer.writeAll(mem.asBytes(&hdr));
684 try writer.writeAll(self.data);
685}
686
657pub fn locals(self: Object) []const Symbol.Index {687pub fn locals(self: Object) []const Symbol.Index {
658 const end = self.first_global orelse self.symbols.items.len;688 const end = self.first_global orelse self.symbols.items.len;
659 return self.symbols.items[0..end];689 return self.symbols.items[0..end];
src/link/Elf/ZigObject.zig+8-19
...@@ -3,7 +3,6 @@...@@ -3,7 +3,6 @@
3//! and any relocations that may have been emitted.3//! and any relocations that may have been emitted.
4//! Think about this as fake in-memory Object file for the Zig module.4//! Think about this as fake in-memory Object file for the Zig module.
55
6/// Path is owned by Module and lives as long as *Module.
7path: []const u8,6path: []const u8,
8index: File.Index,7index: File.Index,
98
...@@ -78,7 +77,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -78,7 +77,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
78 try self.atoms.append(gpa, 0); // null input section77 try self.atoms.append(gpa, 0); // null input section
79 try self.strtab.buffer.append(gpa, 0);78 try self.strtab.buffer.append(gpa, 0);
8079
81 const name_off = try self.strtab.insert(gpa, std.fs.path.stem(self.path));80 const name_off = try self.strtab.insert(gpa, self.path);
82 const symbol_index = try elf_file.addSymbol();81 const symbol_index = try elf_file.addSymbol();
83 try self.local_symbols.append(gpa, symbol_index);82 try self.local_symbols.append(gpa, symbol_index);
84 const symbol_ptr = elf_file.symbol(symbol_index);83 const symbol_ptr = elf_file.symbol(symbol_index);
...@@ -98,6 +97,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -98,6 +97,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
98}97}
9998
100pub fn deinit(self: *ZigObject, allocator: Allocator) void {99pub fn deinit(self: *ZigObject, allocator: Allocator) void {
100 allocator.free(self.path);
101 self.local_esyms.deinit(allocator);101 self.local_esyms.deinit(allocator);
102 self.global_esyms.deinit(allocator);102 self.global_esyms.deinit(allocator);
103 self.strtab.deinit(allocator);103 self.strtab.deinit(allocator);
...@@ -512,25 +512,13 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *...@@ -512,25 +512,13 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *
512 const global = elf_file.symbol(global_index);512 const global = elf_file.symbol(global_index);
513 const file_ptr = global.file(elf_file).?;513 const file_ptr = global.file(elf_file).?;
514 assert(file_ptr.index() == self.index);514 assert(file_ptr.index() == self.index);
515 if (global.type(elf_file) == elf.SHN_UNDEF) continue;515 if (global.outputShndx() == null) continue;
516516
517 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));517 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
518 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });518 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
519 }519 }
520}520}
521521
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 if (name.len <= 15) return;
530 const name_off = try ar_strtab.insert(allocator, name);
531 self.output_ar_state.name_off = name_off;
532}
533
534pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void {522pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void {
535 var end_pos: u64 = elf_file.shdr_table_offset.?;523 var end_pos: u64 = elf_file.shdr_table_offset.?;
536 for (elf_file.shdrs.items) |shdr| {524 for (elf_file.shdrs.items) |shdr| {
...@@ -549,11 +537,12 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {...@@ -549,11 +537,12 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
549 const amt = try elf_file.base.file.?.preadAll(contents, 0);537 const amt = try elf_file.base.file.?.preadAll(contents, 0);
550 if (amt != self.output_ar_state.size) return error.InputOutput;538 if (amt != self.output_ar_state.size) return error.InputOutput;
551539
552 const name = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(self.path)});540 const name = self.path;
553 defer gpa.free(name);
554
555 const hdr = Archive.setArHdr(.{541 const hdr = Archive.setArHdr(.{
556 .name = if (name.len <= 15) .{ .name = name } else .{ .name_off = self.output_ar_state.name_off },542 .name = if (name.len <= Archive.max_member_name_len)
543 .{ .name = name }
544 else
545 .{ .name_off = self.output_ar_state.name_off },
557 .size = @intCast(size),546 .size = @intCast(size),
558 });547 });
559 try writer.writeAll(mem.asBytes(&hdr));548 try writer.writeAll(mem.asBytes(&hdr));
src/link/Elf/file.zig+13-7
...@@ -199,23 +199,30 @@ pub const File = union(enum) {...@@ -199,23 +199,30 @@ pub const File = union(enum) {
199 pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {199 pub fn updateArSymtab(file: File, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
200 return switch (file) {200 return switch (file) {
201 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),201 .zig_object => |x| x.updateArSymtab(ar_symtab, elf_file),
202 .object => @panic("TODO"),202 .object => |x| x.updateArSymtab(ar_symtab, elf_file),
203 inline else => unreachable,203 inline else => unreachable,
204 };204 };
205 }205 }
206206
207 pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void {207 pub fn updateArStrtab(file: File, allocator: Allocator, ar_strtab: *Archive.ArStrtab) !void {
208 return switch (file) {208 const path = switch (file) {
209 .zig_object => |x| x.updateArStrtab(allocator, ar_strtab),209 .zig_object => |x| x.path,
210 .object => @panic("TODO"),210 .object => |x| x.path,
211 inline else => unreachable,
212 };
213 const state = switch (file) {
214 .zig_object => |x| &x.output_ar_state,
215 .object => |x| &x.output_ar_state,
211 inline else => unreachable,216 inline else => unreachable,
212 };217 };
218 if (path.len <= Archive.max_member_name_len) return;
219 state.name_off = try ar_strtab.insert(allocator, path);
213 }220 }
214221
215 pub fn updateArSize(file: File, elf_file: *Elf) void {222 pub fn updateArSize(file: File, elf_file: *Elf) void {
216 return switch (file) {223 return switch (file) {
217 .zig_object => |x| x.updateArSize(elf_file),224 .zig_object => |x| x.updateArSize(elf_file),
218 .object => @panic("TODO"),225 .object => |x| x.updateArSize(),
219 inline else => unreachable,226 inline else => unreachable,
220 };227 };
221 }228 }
...@@ -223,8 +230,7 @@ pub const File = union(enum) {...@@ -223,8 +230,7 @@ pub const File = union(enum) {
223 pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void {230 pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void {
224 return switch (file) {231 return switch (file) {
225 .zig_object => |x| x.writeAr(elf_file, writer),232 .zig_object => |x| x.writeAr(elf_file, writer),
226 // .object => |x| x.writeAr(elf_file, writer),233 .object => |x| x.writeAr(writer),
227 .object => @panic("TODO"),
228 inline else => unreachable,234 inline else => unreachable,
229 };235 };
230 }236 }