Commit e3b82eaa66

Jakub Konka <kubkon@jakubkonka.com>
2023-11-04 00:08:55
elf: do not store filename in strtab unless longer than 15 chars
1 parent acd700a
Changed files (3)
src/link/Elf/Archive.zig
@@ -61,14 +61,15 @@ pub fn parse(self: *Archive, elf_file: *Elf) !void {
         const object_name = blk: {
             if (name[0] == '/') {
                 const off = try std.fmt.parseInt(u32, name[1..], 10);
-                break :blk self.getString(off);
+                const object_name = self.getString(off);
+                break :blk try gpa.dupe(u8, object_name[0 .. object_name.len - 1]); // To account for trailing '/'
             }
-            break :blk name;
+            break :blk try gpa.dupe(u8, name);
         };
 
         const object = Object{
             .archive = try gpa.dupe(u8, self.path),
-            .path = try gpa.dupe(u8, object_name[0 .. object_name.len - 1]), // To account for trailing '/'
+            .path = object_name,
             .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),
             .index = undefined,
             .alive = false,
@@ -86,8 +87,12 @@ fn getString(self: Archive, off: u32) []const u8 {
 }
 
 pub fn setArHdr(opts: struct {
-    kind: enum { symtab, strtab, object },
-    name_off: u32,
+    name: union(enum) {
+        symtab: void,
+        strtab: void,
+        name: []const u8,
+        name_off: u32,
+    },
     size: u32,
 }) ar_hdr {
     var hdr: ar_hdr = .{
@@ -105,10 +110,11 @@ pub fn setArHdr(opts: struct {
     {
         var stream = std.io.fixedBufferStream(&hdr.ar_name);
         const writer = stream.writer();
-        switch (opts.kind) {
+        switch (opts.name) {
             .symtab => writer.print("{s}", .{Archive.SYM64NAME}) catch unreachable,
             .strtab => writer.print("//", .{}) catch unreachable,
-            .object => writer.print("/{d}", .{opts.name_off}) catch unreachable,
+            .name => |x| writer.print("{s}", .{x}) catch unreachable,
+            .name_off => |x| writer.print("/{d}", .{x}) catch unreachable,
         }
     }
     {
@@ -213,7 +219,7 @@ pub const ArSymtab = struct {
 
     pub fn write(ar: ArSymtab, kind: enum { p32, p64 }, elf_file: *Elf, writer: anytype) !void {
         assert(kind == .p64); // TODO p32
-        const hdr = setArHdr(.{ .kind = .symtab, .name_off = 0, .size = @intCast(ar.size(.p64)) });
+        const hdr = setArHdr(.{ .name = .symtab, .size = @intCast(ar.size(.p64)) });
         try writer.writeAll(mem.asBytes(&hdr));
 
         const gpa = elf_file.base.allocator;
@@ -314,7 +320,7 @@ pub const ArStrtab = struct {
     }
 
     pub fn write(ar: ArStrtab, writer: anytype) !void {
-        const hdr = setArHdr(.{ .kind = .strtab, .name_off = 0, .size = @intCast(ar.size()) });
+        const hdr = setArHdr(.{ .name = .strtab, .size = @intCast(ar.size()) });
         try writer.writeAll(mem.asBytes(&hdr));
         try writer.writeAll(ar.buffer.items);
     }
src/link/Elf/ZigObject.zig
@@ -526,6 +526,7 @@ pub fn updateArStrtab(
 ) error{OutOfMemory}!void {
     const name = try std.fmt.allocPrint(allocator, "{s}.o", .{std.fs.path.stem(self.path)});
     defer allocator.free(name);
+    if (name.len <= 15) return;
     const name_off = try ar_strtab.insert(allocator, name);
     self.output_ar_state.name_off = name_off;
 }
@@ -540,13 +541,18 @@ pub fn updateArSize(self: *ZigObject, elf_file: *Elf) void {
 
 pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
     const gpa = elf_file.base.allocator;
+
     const contents = try gpa.alloc(u8, self.output_ar_state.size);
     defer gpa.free(contents);
+
     const amt = try elf_file.base.file.?.preadAll(contents, 0);
     if (amt != self.output_ar_state.size) return error.InputOutput;
+
+    const name = try std.fmt.allocPrint(gpa, "{s}.o", .{std.fs.path.stem(self.path)});
+    defer gpa.free(name);
+
     const hdr = Archive.setArHdr(.{
-        .kind = .object,
-        .name_off = self.output_ar_state.name_off,
+        .name = if (name.len <= 15) .{ .name = name } else .{ .name_off = self.output_ar_state.name_off },
         .size = @intCast(self.output_ar_state.size),
     });
     try writer.writeAll(mem.asBytes(&hdr));
src/link/Elf.zig
@@ -1572,8 +1572,11 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
     const total_size: u64 = blk: {
         var pos: u64 = Archive.SARMAG;
         pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64);
-        pos = mem.alignForward(u64, pos, 2);
-        pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size();
+
+        if (ar_strtab.size() > 0) {
+            pos = mem.alignForward(u64, pos, 2);
+            pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size();
+        }
 
         if (self.zigObjectPtr()) |zig_object| {
             pos = mem.alignForward(u64, pos, 2);
@@ -1598,19 +1601,22 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
 
     // Write symtab
     try ar_symtab.write(.p64, self, buffer.writer());
-    if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
 
     // Write strtab
-    try ar_strtab.write(buffer.writer());
-    if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
+    if (ar_strtab.size() > 0) {
+        if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
+        try ar_strtab.write(buffer.writer());
+    }
 
     // Write object files
     if (self.zigObjectPtr()) |zig_object| {
+        if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
         try zig_object.writeAr(self, buffer.writer());
     }
 
     assert(buffer.items.len == total_size);
 
+    try self.base.file.?.setEndPos(total_size);
     try self.base.file.?.pwriteAll(buffer.items, 0);
 }