authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:03:38-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:14:16-04:00
log40901440a620caf1849c627cff0d3a96eda273f5
tree951d56b9233963cec61f08b0620dee9b43422481
parentc4478e078b88c836b53d0e42065b0f68e62c0add

Elf2: simplify archive loading


2 files changed, 36 insertions(+), 67 deletions(-)

src/link/Elf/Archive.zig+1-3
...@@ -34,8 +34,6 @@ pub fn parse(...@@ -34,8 +34,6 @@ pub fn parse(
34 defer strtab.deinit(gpa);34 defer strtab.deinit(gpa);
3535
36 while (pos < size) {36 while (pos < size) {
37 pos = mem.alignForward(usize, pos, 2);
38
39 var hdr: elf.ar_hdr = undefined;37 var hdr: elf.ar_hdr = undefined;
40 {38 {
41 const n = try handle.preadAll(mem.asBytes(&hdr), pos);39 const n = try handle.preadAll(mem.asBytes(&hdr), pos);
...@@ -50,7 +48,7 @@ pub fn parse(...@@ -50,7 +48,7 @@ pub fn parse(
50 }48 }
5149
52 const obj_size = try hdr.size();50 const obj_size = try hdr.size();
53 defer pos += obj_size;51 defer pos = std.mem.alignForward(usize, pos + obj_size, 2);
5452
55 if (hdr.isSymtab() or hdr.isSymtab64()) continue;53 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
56 if (hdr.isStrtab()) {54 if (hdr.isStrtab()) {
src/link/Elf2.zig+35-64
...@@ -1268,62 +1268,29 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||...@@ -1268,62 +1268,29 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
1268 switch (input) {1268 switch (input) {
1269 else => {},1269 else => {},
1270 .object => |object| {1270 .object => |object| {
1271 var fsr: FileSliceReader = .init(object.file.reader(io, &.{}));1271 var fr = object.file.reader(io, &buf);
1272 fsr.reset(try fsr.file.getSize(), &buf);1272 elf.loadObject(object.path, null, &fr, .{
1273 elf.loadObject(object.path, null, &fsr) catch |err| switch (err) {1273 .offset = fr.logicalPos(),
1274 error.ReadFailed => return fsr.file.err.?,1274 .size = try fr.getSize(),
1275 }) catch |err| switch (err) {
1276 error.ReadFailed => return fr.err.?,
1275 else => |e| return e,1277 else => |e| return e,
1276 };1278 };
1277 },1279 },
1278 .archive => |archive| {1280 .archive => |archive| {
1279 var fsr: FileSliceReader = .init(archive.file.reader(io, &buf));1281 var fr = archive.file.reader(io, &buf);
1280 elf.loadArchive(archive.path, &fsr) catch |err| switch (err) {1282 elf.loadArchive(archive.path, &fr) catch |err| switch (err) {
1281 error.ReadFailed => return fsr.file.err.?,1283 error.ReadFailed => return fr.err.?,
1282 else => |e| return e,1284 else => |e| return e,
1283 };1285 };
1284 },1286 },
1285 }1287 }
1286}1288}
1287const FileSliceReader = struct {1289fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
1288 file: std.Io.File.Reader,
1289 file_location: MappedFile.Node.FileLocation,
1290 reader: std.Io.Reader.Limited,
1291
1292 pub fn init(file: std.Io.File.Reader) FileSliceReader {
1293 return .{ .file = file, .file_location = undefined, .reader = undefined };
1294 }
1295
1296 pub fn reset(fsr: *FileSliceReader, size: u64, buffer: []u8) void {
1297 fsr.file_location = .{
1298 .offset = fsr.file.logicalPos(),
1299 .size = size,
1300 };
1301 fsr.reader = .init(&fsr.file.interface, .limited(@intCast(size)), buffer);
1302 }
1303
1304 pub fn pos(fsr: *const FileSliceReader) u64 {
1305 return fsr.file.logicalPos() - fsr.file_location.offset;
1306 }
1307
1308 pub fn logicalPos(fsr: *const FileSliceReader) u64 {
1309 return fsr.pos() - fsr.reader.interface.bufferedLen();
1310 }
1311
1312 pub fn seekTo(fsr: *FileSliceReader, offset: u64) std.Io.File.Reader.SeekError!void {
1313 if (offset > fsr.file_location.size) return error.EndOfStream;
1314 const logical_pos = fsr.logicalPos();
1315 if (offset < logical_pos or offset >= fsr.pos()) {
1316 fsr.reader.interface.tossBuffered();
1317 try fsr.file.seekTo(fsr.file_location.offset + offset);
1318 fsr.reader.remaining = .limited(@intCast(fsr.file_location.size - offset));
1319 } else fsr.reader.interface.toss(@intCast(offset - logical_pos));
1320 }
1321};
1322fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !void {
1323 const comp = elf.base.comp;1290 const comp = elf.base.comp;
1324 const gpa = comp.gpa;1291 const gpa = comp.gpa;
1325 const diags = &comp.link_diags;1292 const diags = &comp.link_diags;
1326 const r = &fsr.file.interface;1293 const r = &fr.interface;
13271294
1328 log.debug("loadArchive({f})", .{path.fmtEscapeString()});1295 log.debug("loadArchive({f})", .{path.fmtEscapeString()});
1329 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG))1296 if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG))
...@@ -1333,6 +1300,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo...@@ -1333,6 +1300,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo
1333 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {1300 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
1334 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))1301 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))
1335 return diags.failParse(path, "bad file magic", .{});1302 return diags.failParse(path, "bad file magic", .{});
1303 const offset = fr.logicalPos();
1336 const size = header.size() catch1304 const size = header.size() catch
1337 return diags.failParse(path, "bad member size", .{});1305 return diags.failParse(path, "bad member size", .{});
1338 if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) {1306 if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) {
...@@ -1361,15 +1329,11 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo...@@ -1361,15 +1329,11 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo
1361 error.Overflow => return diags.failParse(path, "bad member name offset", .{}),1329 error.Overflow => return diags.failParse(path, "bad member name offset", .{}),
1362 };1330 };
1363 if (!std.mem.endsWith(u8, member, ".o")) break :load_object;1331 if (!std.mem.endsWith(u8, member, ".o")) break :load_object;
1364 var buf: [4096]u8 = undefined;1332 try elf.loadObject(path, member, fr, .{ .offset = offset, .size = size });
1365 fsr.reset(size, &buf);
1366 try elf.loadObject(path, member, fsr);
1367 try fsr.seekTo(size);
1368 continue;
1369 }1333 }
1370 try r.discardAll(size);1334 try fr.seekTo(std.mem.alignForward(u64, offset + size, 2));
1371 } else |err| switch (err) {1335 } else |err| switch (err) {
1372 error.EndOfStream => if (!fsr.file.atEnd()) return error.EndOfStream,1336 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
1373 else => |e| return e,1337 else => |e| return e,
1374 }1338 }
1375}1339}
...@@ -1379,11 +1343,17 @@ fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEsc...@@ -1379,11 +1343,17 @@ fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEsc
1379fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {1343fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
1380 try w.print("({f})", .{std.zig.fmtString(member orelse return)});1344 try w.print("({f})", .{std.zig.fmtString(member orelse return)});
1381}1345}
1382fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *FileSliceReader) !void {1346fn loadObject(
1347 elf: *Elf,
1348 path: std.Build.Cache.Path,
1349 member: ?[]const u8,
1350 fr: *std.Io.File.Reader,
1351 fl: MappedFile.Node.FileLocation,
1352) !void {
1383 const comp = elf.base.comp;1353 const comp = elf.base.comp;
1384 const gpa = comp.gpa;1354 const gpa = comp.gpa;
1385 const diags = &comp.link_diags;1355 const diags = &comp.link_diags;
1386 const r = &fsr.reader.interface;1356 const r = &fr.interface;
13871357
1388 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);1358 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
1389 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });1359 log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) });
...@@ -1411,11 +1381,13 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1411,11 +1381,13 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1411 if (ehdr.machine != elf.ehdrField(.machine))1381 if (ehdr.machine != elf.ehdrField(.machine))
1412 return diags.failParse(path, "bad machine", .{});1382 return diags.failParse(path, "bad machine", .{});
1413 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;1383 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
1384 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)
1385 return diags.failParse(path, "bad section header offset/size", .{});
1414 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))1386 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
1415 return diags.failParse(path, "unsupported shentsize", .{});1387 return diags.failParse(path, "unsupported shentsize", .{});
1416 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);1388 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);
1417 defer gpa.free(sections);1389 defer gpa.free(sections);
1418 try fsr.seekTo(ehdr.shoff);1390 try fr.seekTo(fl.offset + ehdr.shoff);
1419 for (sections) |*section| {1391 for (sections) |*section| {
1420 section.* = .{1392 section.* = .{
1421 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),1393 .shdr = try r.peekStruct(ElfN.Shdr, target_endian),
...@@ -1424,7 +1396,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1424,7 +1396,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1424 try r.discardAll(ehdr.shentsize);1396 try r.discardAll(ehdr.shentsize);
1425 switch (section.shdr.type) {1397 switch (section.shdr.type) {
1426 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},1398 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
1427 else => if (section.shdr.offset + section.shdr.size > fsr.file_location.size)1399 else => if (section.shdr.offset + section.shdr.size > fl.size)
1428 return diags.failParse(path, "bad section offset/size", .{}),1400 return diags.failParse(path, "bad section offset/size", .{}),
1429 }1401 }
1430 }1402 }
...@@ -1436,7 +1408,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1436,7 +1408,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1436 return diags.failParse(path, "invalid shstrtab type", .{});1408 return diags.failParse(path, "invalid shstrtab type", .{});
1437 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));1409 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
1438 errdefer gpa.free(shstrtab);1410 errdefer gpa.free(shstrtab);
1439 try fsr.seekTo(shdr.offset);1411 try fr.seekTo(fl.offset + shdr.offset);
1440 try r.readSliceAll(shstrtab);1412 try r.readSliceAll(shstrtab);
1441 break :shstrtab shstrtab;1413 break :shstrtab shstrtab;
1442 };1414 };
...@@ -1470,7 +1442,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1470,7 +1442,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1470 .ii = ii,1442 .ii = ii,
1471 .si = section.si,1443 .si = section.si,
1472 .file_location = .{1444 .file_location = .{
1473 .offset = fsr.file_location.offset + section.shdr.offset,1445 .offset = fl.offset + section.shdr.offset,
1474 .size = section.shdr.size,1446 .size = section.shdr.size,
1475 },1447 },
1476 };1448 };
...@@ -1492,7 +1464,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1492,7 +1464,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1492 return diags.failParse(path, "invalid strtab type", .{});1464 return diags.failParse(path, "invalid strtab type", .{});
1493 const strtab = try gpa.alloc(u8, @intCast(shdr.size));1465 const strtab = try gpa.alloc(u8, @intCast(shdr.size));
1494 errdefer gpa.free(strtab);1466 errdefer gpa.free(strtab);
1495 try fsr.seekTo(shdr.offset);1467 try fr.seekTo(fl.offset + shdr.offset);
1496 try r.readSliceAll(strtab);1468 try r.readSliceAll(strtab);
1497 break :strtab strtab;1469 break :strtab strtab;
1498 };1470 };
...@@ -1507,12 +1479,11 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1507,12 +1479,11 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1507 .{ symtab.shdr.size, symtab.shdr.entsize },1479 .{ symtab.shdr.size, symtab.shdr.entsize },
1508 );1480 );
1509 symmap.clearRetainingCapacity();1481 symmap.clearRetainingCapacity();
1510 try symmap.resize(gpa, symnum);1482 try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue);
1511 try elf.symtab.ensureUnusedCapacity(gpa, symnum);1483 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
1512 try elf.globals.ensureUnusedCapacity(gpa, symnum);1484 try elf.globals.ensureUnusedCapacity(gpa, symnum);
1513 try fsr.seekTo(symtab.shdr.offset + symtab.shdr.entsize);1485 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
1514 symmap.items[0] = .null;1486 for (symmap.items) |*si| {
1515 for (symmap.items[1..]) |*si| {
1516 si.* = .null;1487 si.* = .null;
1517 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);1488 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
1518 try r.discardAll64(symtab.shdr.entsize);1489 try r.discardAll64(symtab.shdr.entsize);
...@@ -1594,12 +1565,12 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *...@@ -1594,12 +1565,12 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
1594 .{ rels.shdr.size, rels.shdr.entsize },1565 .{ rels.shdr.size, rels.shdr.entsize },
1595 );1566 );
1596 try elf.relocs.ensureUnusedCapacity(gpa, relnum);1567 try elf.relocs.ensureUnusedCapacity(gpa, relnum);
1597 try fsr.seekTo(rels.shdr.offset);1568 try fr.seekTo(fl.offset + rels.shdr.offset);
1598 for (0..relnum) |_| {1569 for (0..relnum) |_| {
1599 const rel = try r.peekStruct(Rel, target_endian);1570 const rel = try r.peekStruct(Rel, target_endian);
1600 try r.discardAll64(rels.shdr.entsize);1571 try r.discardAll64(rels.shdr.entsize);
1601 if (rel.info.sym >= symnum) continue;1572 if (rel.info.sym >= symnum) continue;
1602 const target_si = symmap.items[rel.info.sym];1573 const target_si = symmap.items[rel.info.sym - 1];
1603 if (target_si == .null) continue;1574 if (target_si == .null) continue;
1604 elf.addRelocAssumeCapacity(1575 elf.addRelocAssumeCapacity(
1605 loc_sec.si,1576 loc_sec.si,