| author | |
| committer | |
| log | 9ec0cf23ca5e26e7d6a8f0f053505b05b56bf645 |
| tree | 6f5c3ec4a83091c25cf97f50a41c2307c04f5fe8 |
| parent | 8addf53fb5046a65c6fd0c0d2e7894be60468132 |
| parent | c22bb3805821d7ffe60e048f1efe362aad703668 |
| signature |
elf: reduce memory pressure12 files changed, 961 insertions(+), 848 deletions(-)
CMakeLists.txt+1| ... | @@ -593,6 +593,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -593,6 +593,7 @@ set(ZIG_STAGE2_SOURCES |
| 593 | "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig" | 593 | "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig" |
| 594 | "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig" | 594 | "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig" |
| 595 | "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig" | 595 | "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig" |
| 596 | "${CMAKE_SOURCE_DIR}/src/link/Elf/relocatable.zig" | ||
| 596 | "${CMAKE_SOURCE_DIR}/src/link/Elf/synthetic_sections.zig" | 597 | "${CMAKE_SOURCE_DIR}/src/link/Elf/synthetic_sections.zig" |
| 597 | "${CMAKE_SOURCE_DIR}/src/link/MachO.zig" | 598 | "${CMAKE_SOURCE_DIR}/src/link/MachO.zig" |
| 598 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig" | 599 | "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig" |
src/link/Elf.zig+83-556| ... | @@ -35,6 +35,10 @@ llvm_object: ?*LlvmObject = null, | ... | @@ -35,6 +35,10 @@ llvm_object: ?*LlvmObject = null, |
| 35 | /// Index of each input file also encodes the priority or precedence of one input file | 35 | /// Index of each input file also encodes the priority or precedence of one input file |
| 36 | /// over another. | 36 | /// over another. |
| 37 | files: std.MultiArrayList(File.Entry) = .{}, | 37 | files: std.MultiArrayList(File.Entry) = .{}, |
| 38 | /// Long-lived list of all file descriptors. | ||
| 39 | /// We store them globally rather than per actual File so that we can re-use | ||
| 40 | /// one file handle per every object file within an archive. | ||
| 41 | file_handles: std.ArrayListUnmanaged(File.Handle) = .{}, | ||
| 38 | zig_object_index: ?File.Index = null, | 42 | zig_object_index: ?File.Index = null, |
| 39 | linker_defined_index: ?File.Index = null, | 43 | linker_defined_index: ?File.Index = null, |
| 40 | objects: std.ArrayListUnmanaged(File.Index) = .{}, | 44 | objects: std.ArrayListUnmanaged(File.Index) = .{}, |
| ... | @@ -444,6 +448,11 @@ pub fn deinit(self: *Elf) void { | ... | @@ -444,6 +448,11 @@ pub fn deinit(self: *Elf) void { |
| 444 | 448 | ||
| 445 | if (self.llvm_object) |llvm_object| llvm_object.deinit(); | 449 | if (self.llvm_object) |llvm_object| llvm_object.deinit(); |
| 446 | 450 | ||
| 451 | for (self.file_handles.items) |fh| { | ||
| 452 | fh.close(); | ||
| 453 | } | ||
| 454 | self.file_handles.deinit(gpa); | ||
| 455 | |||
| 447 | for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) { | 456 | for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) { |
| 448 | .null => {}, | 457 | .null => {}, |
| 449 | .zig_object => data.zig_object.deinit(gpa), | 458 | .zig_object => data.zig_object.deinit(gpa), |
| ... | @@ -561,7 +570,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | ... | @@ -561,7 +570,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 561 | return null; | 570 | return null; |
| 562 | } | 571 | } |
| 563 | 572 | ||
| 564 | fn allocatedSize(self: *Elf, start: u64) u64 { | 573 | pub fn allocatedSize(self: *Elf, start: u64) u64 { |
| 565 | if (start == 0) return 0; | 574 | if (start == 0) return 0; |
| 566 | var min_pos: u64 = std.math.maxInt(u64); | 575 | var min_pos: u64 = std.math.maxInt(u64); |
| 567 | if (self.shdr_table_offset) |off| { | 576 | if (self.shdr_table_offset) |off| { |
| ... | @@ -588,7 +597,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 { | ... | @@ -588,7 +597,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 { |
| 588 | return min_pos - start; | 597 | return min_pos - start; |
| 589 | } | 598 | } |
| 590 | 599 | ||
| 591 | fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { | 600 | pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 592 | var start: u64 = 0; | 601 | var start: u64 = 0; |
| 593 | while (self.detectAllocCollision(start, object_size)) |item_end| { | 602 | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| 594 | start = mem.alignForward(u64, item_end, min_alignment); | 603 | start = mem.alignForward(u64, item_end, min_alignment); |
| ... | @@ -1066,6 +1075,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1066,6 +1075,10 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1066 | // --verbose-link | 1075 | // --verbose-link |
| 1067 | if (comp.verbose_link) try self.dumpArgv(comp); | 1076 | if (comp.verbose_link) try self.dumpArgv(comp); |
| 1068 | 1077 | ||
| 1078 | if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); | ||
| 1079 | if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); | ||
| 1080 | if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); | ||
| 1081 | |||
| 1069 | const csu = try CsuObjects.init(arena, comp); | 1082 | const csu = try CsuObjects.init(arena, comp); |
| 1070 | const compiler_rt_path: ?[]const u8 = blk: { | 1083 | const compiler_rt_path: ?[]const u8 = blk: { |
| 1071 | if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; | 1084 | if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; |
| ... | @@ -1073,10 +1086,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1073,10 +1086,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1073 | break :blk null; | 1086 | break :blk null; |
| 1074 | }; | 1087 | }; |
| 1075 | 1088 | ||
| 1076 | if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); | ||
| 1077 | if (self.base.isStaticLib()) return self.flushStaticLib(comp, module_obj_path); | ||
| 1078 | if (self.base.isObject()) return self.flushObject(comp, module_obj_path); | ||
| 1079 | |||
| 1080 | // Here we will parse input positional and library files (if referenced). | 1089 | // Here we will parse input positional and library files (if referenced). |
| 1081 | // This will roughly match in any linker backend we support. | 1090 | // This will roughly match in any linker backend we support. |
| 1082 | var positionals = std.ArrayList(Compilation.LinkObject).init(arena); | 1091 | var positionals = std.ArrayList(Compilation.LinkObject).init(arena); |
| ... | @@ -1240,16 +1249,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1240,16 +1249,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1240 | 1249 | ||
| 1241 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | 1250 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1242 | 1251 | ||
| 1243 | // Init all objects | ||
| 1244 | for (self.objects.items) |index| { | ||
| 1245 | try self.file(index).?.object.init(self); | ||
| 1246 | } | ||
| 1247 | for (self.shared_objects.items) |index| { | ||
| 1248 | try self.file(index).?.shared_object.init(self); | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 1252 | |||
| 1253 | // Dedup shared objects | 1252 | // Dedup shared objects |
| 1254 | { | 1253 | { |
| 1255 | var seen_dsos = std.StringHashMap(void).init(gpa); | 1254 | var seen_dsos = std.StringHashMap(void).init(gpa); |
| ... | @@ -1382,222 +1381,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) | ... | @@ -1382,222 +1381,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1382 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | 1381 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1383 | } | 1382 | } |
| 1384 | 1383 | ||
| 1385 | pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { | ||
| 1386 | const gpa = comp.gpa; | ||
| 1387 | |||
| 1388 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | ||
| 1389 | defer positionals.deinit(); | ||
| 1390 | |||
| 1391 | try positionals.ensureUnusedCapacity(comp.objects.len); | ||
| 1392 | positionals.appendSliceAssumeCapacity(comp.objects); | ||
| 1393 | |||
| 1394 | // This is a set of object files emitted by clang in a single `build-exe` invocation. | ||
| 1395 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up | ||
| 1396 | // in this set. | ||
| 1397 | for (comp.c_object_table.keys()) |key| { | ||
| 1398 | try positionals.append(.{ .path = key.status.success.object_path }); | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | ||
| 1402 | |||
| 1403 | for (positionals.items) |obj| { | ||
| 1404 | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | ||
| 1405 | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported | ||
| 1406 | else => |e| try self.reportParseError( | ||
| 1407 | obj.path, | ||
| 1408 | "unexpected error: parsing input file failed with error {s}", | ||
| 1409 | .{@errorName(e)}, | ||
| 1410 | ), | ||
| 1411 | }; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 1415 | |||
| 1416 | // First, we flush relocatable object file generated with our backends. | ||
| 1417 | if (self.zigObjectPtr()) |zig_object| { | ||
| 1418 | zig_object.resolveSymbols(self); | ||
| 1419 | zig_object.claimUnresolvedObject(self); | ||
| 1420 | |||
| 1421 | try self.initSymtab(); | ||
| 1422 | try self.initShStrtab(); | ||
| 1423 | try self.sortShdrs(); | ||
| 1424 | try zig_object.addAtomsToRelaSections(self); | ||
| 1425 | try self.updateSectionSizesObject(); | ||
| 1426 | |||
| 1427 | try self.allocateAllocSectionsObject(); | ||
| 1428 | try self.allocateNonAllocSections(); | ||
| 1429 | |||
| 1430 | if (build_options.enable_logging) { | ||
| 1431 | state_log.debug("{}", .{self.dumpState()}); | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | try self.writeSyntheticSectionsObject(); | ||
| 1435 | try self.writeShdrTable(); | ||
| 1436 | try self.writeElfHeader(); | ||
| 1437 | |||
| 1438 | // TODO we can avoid reading in the file contents we just wrote if we give the linker | ||
| 1439 | // ability to write directly to a buffer. | ||
| 1440 | try zig_object.readFileContents(self); | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | var files = std.ArrayList(File.Index).init(gpa); | ||
| 1444 | defer files.deinit(); | ||
| 1445 | try files.ensureTotalCapacityPrecise(self.objects.items.len + 1); | ||
| 1446 | if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index); | ||
| 1447 | for (self.objects.items) |index| files.appendAssumeCapacity(index); | ||
| 1448 | |||
| 1449 | // Update ar symtab from parsed objects | ||
| 1450 | var ar_symtab: Archive.ArSymtab = .{}; | ||
| 1451 | defer ar_symtab.deinit(gpa); | ||
| 1452 | |||
| 1453 | for (files.items) |index| { | ||
| 1454 | try self.file(index).?.updateArSymtab(&ar_symtab, self); | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | ar_symtab.sort(); | ||
| 1458 | |||
| 1459 | // Save object paths in filenames strtab. | ||
| 1460 | var ar_strtab: Archive.ArStrtab = .{}; | ||
| 1461 | defer ar_strtab.deinit(gpa); | ||
| 1462 | |||
| 1463 | for (files.items) |index| { | ||
| 1464 | const file_ptr = self.file(index).?; | ||
| 1465 | try file_ptr.updateArStrtab(gpa, &ar_strtab); | ||
| 1466 | file_ptr.updateArSize(); | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | // Update file offsets of contributing objects. | ||
| 1470 | const total_size: usize = blk: { | ||
| 1471 | var pos: usize = elf.ARMAG.len; | ||
| 1472 | pos += @sizeOf(elf.ar_hdr) + ar_symtab.size(.p64); | ||
| 1473 | |||
| 1474 | if (ar_strtab.size() > 0) { | ||
| 1475 | pos = mem.alignForward(usize, pos, 2); | ||
| 1476 | pos += @sizeOf(elf.ar_hdr) + ar_strtab.size(); | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | for (files.items) |index| { | ||
| 1480 | const file_ptr = self.file(index).?; | ||
| 1481 | const state = switch (file_ptr) { | ||
| 1482 | .zig_object => |x| &x.output_ar_state, | ||
| 1483 | .object => |x| &x.output_ar_state, | ||
| 1484 | else => unreachable, | ||
| 1485 | }; | ||
| 1486 | pos = mem.alignForward(usize, pos, 2); | ||
| 1487 | state.file_off = pos; | ||
| 1488 | pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow); | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | break :blk pos; | ||
| 1492 | }; | ||
| 1493 | |||
| 1494 | if (build_options.enable_logging) { | ||
| 1495 | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)}); | ||
| 1496 | state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); | ||
| 1497 | } | ||
| 1498 | |||
| 1499 | var buffer = std.ArrayList(u8).init(gpa); | ||
| 1500 | defer buffer.deinit(); | ||
| 1501 | try buffer.ensureTotalCapacityPrecise(total_size); | ||
| 1502 | |||
| 1503 | // Write magic | ||
| 1504 | try buffer.writer().writeAll(elf.ARMAG); | ||
| 1505 | |||
| 1506 | // Write symtab | ||
| 1507 | try ar_symtab.write(.p64, self, buffer.writer()); | ||
| 1508 | |||
| 1509 | // Write strtab | ||
| 1510 | if (ar_strtab.size() > 0) { | ||
| 1511 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); | ||
| 1512 | try ar_strtab.write(buffer.writer()); | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | // Write object files | ||
| 1516 | for (files.items) |index| { | ||
| 1517 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); | ||
| 1518 | try self.file(index).?.writeAr(buffer.writer()); | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | assert(buffer.items.len == total_size); | ||
| 1522 | |||
| 1523 | try self.base.file.?.setEndPos(total_size); | ||
| 1524 | try self.base.file.?.pwriteAll(buffer.items, 0); | ||
| 1525 | |||
| 1526 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { | ||
| 1530 | const gpa = self.base.comp.gpa; | ||
| 1531 | |||
| 1532 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | ||
| 1533 | defer positionals.deinit(); | ||
| 1534 | try positionals.ensureUnusedCapacity(comp.objects.len); | ||
| 1535 | positionals.appendSliceAssumeCapacity(comp.objects); | ||
| 1536 | |||
| 1537 | // This is a set of object files emitted by clang in a single `build-exe` invocation. | ||
| 1538 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up | ||
| 1539 | // in this set. | ||
| 1540 | for (comp.c_object_table.keys()) |key| { | ||
| 1541 | try positionals.append(.{ .path = key.status.success.object_path }); | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | ||
| 1545 | |||
| 1546 | for (positionals.items) |obj| { | ||
| 1547 | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | ||
| 1548 | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported | ||
| 1549 | else => |e| try self.reportParseError( | ||
| 1550 | obj.path, | ||
| 1551 | "unexpected error: parsing input file failed with error {s}", | ||
| 1552 | .{@errorName(e)}, | ||
| 1553 | ), | ||
| 1554 | }; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 1558 | |||
| 1559 | // Init all objects | ||
| 1560 | for (self.objects.items) |index| { | ||
| 1561 | try self.file(index).?.object.init(self); | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 1565 | |||
| 1566 | // Now, we are ready to resolve the symbols across all input files. | ||
| 1567 | // We will first resolve the files in the ZigObject, next in the parsed | ||
| 1568 | // input Object files. | ||
| 1569 | self.resolveSymbols(); | ||
| 1570 | self.markEhFrameAtomsDead(); | ||
| 1571 | self.claimUnresolvedObject(); | ||
| 1572 | |||
| 1573 | try self.initSectionsObject(); | ||
| 1574 | try self.sortShdrs(); | ||
| 1575 | if (self.zigObjectPtr()) |zig_object| { | ||
| 1576 | try zig_object.addAtomsToRelaSections(self); | ||
| 1577 | } | ||
| 1578 | for (self.objects.items) |index| { | ||
| 1579 | const object = self.file(index).?.object; | ||
| 1580 | try object.addAtomsToOutputSections(self); | ||
| 1581 | try object.addAtomsToRelaSections(self); | ||
| 1582 | } | ||
| 1583 | try self.updateSectionSizesObject(); | ||
| 1584 | |||
| 1585 | try self.allocateAllocSectionsObject(); | ||
| 1586 | try self.allocateNonAllocSections(); | ||
| 1587 | self.allocateAtoms(); | ||
| 1588 | |||
| 1589 | if (build_options.enable_logging) { | ||
| 1590 | state_log.debug("{}", .{self.dumpState()}); | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | try self.writeAtomsObject(); | ||
| 1594 | try self.writeSyntheticSectionsObject(); | ||
| 1595 | try self.writeShdrTable(); | ||
| 1596 | try self.writeElfHeader(); | ||
| 1597 | |||
| 1598 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 1599 | } | ||
| 1600 | |||
| 1601 | /// --verbose-link output | 1384 | /// --verbose-link output |
| 1602 | fn dumpArgv(self: *Elf, comp: *Compilation) !void { | 1385 | fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1603 | const gpa = self.base.comp.gpa; | 1386 | const gpa = self.base.comp.gpa; |
| ... | @@ -1861,7 +1644,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { | ... | @@ -1861,7 +1644,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1861 | Compilation.dump_argv(argv.items); | 1644 | Compilation.dump_argv(argv.items); |
| 1862 | } | 1645 | } |
| 1863 | 1646 | ||
| 1864 | const ParseError = error{ | 1647 | pub const ParseError = error{ |
| 1865 | MalformedObject, | 1648 | MalformedObject, |
| 1866 | MalformedArchive, | 1649 | MalformedArchive, |
| 1867 | InvalidCpuArch, | 1650 | InvalidCpuArch, |
| ... | @@ -1872,9 +1655,10 @@ const ParseError = error{ | ... | @@ -1872,9 +1655,10 @@ const ParseError = error{ |
| 1872 | FileSystem, | 1655 | FileSystem, |
| 1873 | NotSupported, | 1656 | NotSupported, |
| 1874 | InvalidCharacter, | 1657 | InvalidCharacter, |
| 1658 | UnknownFileType, | ||
| 1875 | } || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError; | 1659 | } || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError; |
| 1876 | 1660 | ||
| 1877 | fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void { | 1661 | pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void { |
| 1878 | const tracy = trace(@src()); | 1662 | const tracy = trace(@src()); |
| 1879 | defer tracy.end(); | 1663 | defer tracy.end(); |
| 1880 | if (try Object.isObject(path)) { | 1664 | if (try Object.isObject(path)) { |
| ... | @@ -1902,13 +1686,13 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void { | ... | @@ -1902,13 +1686,13 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void { |
| 1902 | defer tracy.end(); | 1686 | defer tracy.end(); |
| 1903 | 1687 | ||
| 1904 | const gpa = self.base.comp.gpa; | 1688 | const gpa = self.base.comp.gpa; |
| 1905 | const in_file = try std.fs.cwd().openFile(path, .{}); | 1689 | const handle = try std.fs.cwd().openFile(path, .{}); |
| 1906 | defer in_file.close(); | 1690 | const fh = try self.addFileHandle(handle); |
| 1907 | const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); | 1691 | |
| 1908 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 1692 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1909 | self.files.set(index, .{ .object = .{ | 1693 | self.files.set(index, .{ .object = .{ |
| 1910 | .path = try gpa.dupe(u8, path), | 1694 | .path = try gpa.dupe(u8, path), |
| 1911 | .data = data, | 1695 | .file_handle = fh, |
| 1912 | .index = index, | 1696 | .index = index, |
| 1913 | } }); | 1697 | } }); |
| 1914 | try self.objects.append(gpa, index); | 1698 | try self.objects.append(gpa, index); |
| ... | @@ -1922,12 +1706,12 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void { | ... | @@ -1922,12 +1706,12 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void { |
| 1922 | defer tracy.end(); | 1706 | defer tracy.end(); |
| 1923 | 1707 | ||
| 1924 | const gpa = self.base.comp.gpa; | 1708 | const gpa = self.base.comp.gpa; |
| 1925 | const in_file = try std.fs.cwd().openFile(path, .{}); | 1709 | const handle = try std.fs.cwd().openFile(path, .{}); |
| 1926 | defer in_file.close(); | 1710 | const fh = try self.addFileHandle(handle); |
| 1927 | const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); | 1711 | |
| 1928 | var archive = Archive{ .path = try gpa.dupe(u8, path), .data = data }; | 1712 | var archive = Archive{}; |
| 1929 | defer archive.deinit(gpa); | 1713 | defer archive.deinit(gpa); |
| 1930 | try archive.parse(self); | 1714 | try archive.parse(self, path, fh); |
| 1931 | 1715 | ||
| 1932 | const objects = try archive.objects.toOwnedSlice(gpa); | 1716 | const objects = try archive.objects.toOwnedSlice(gpa); |
| 1933 | defer gpa.free(objects); | 1717 | defer gpa.free(objects); |
| ... | @@ -1948,13 +1732,12 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { | ... | @@ -1948,13 +1732,12 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { |
| 1948 | defer tracy.end(); | 1732 | defer tracy.end(); |
| 1949 | 1733 | ||
| 1950 | const gpa = self.base.comp.gpa; | 1734 | const gpa = self.base.comp.gpa; |
| 1951 | const in_file = try std.fs.cwd().openFile(lib.path, .{}); | 1735 | const handle = try std.fs.cwd().openFile(lib.path, .{}); |
| 1952 | defer in_file.close(); | 1736 | defer handle.close(); |
| 1953 | const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); | 1737 | |
| 1954 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 1738 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1955 | self.files.set(index, .{ .shared_object = .{ | 1739 | self.files.set(index, .{ .shared_object = .{ |
| 1956 | .path = try gpa.dupe(u8, lib.path), | 1740 | .path = try gpa.dupe(u8, lib.path), |
| 1957 | .data = data, | ||
| 1958 | .index = index, | 1741 | .index = index, |
| 1959 | .needed = lib.needed, | 1742 | .needed = lib.needed, |
| 1960 | .alive = lib.needed, | 1743 | .alive = lib.needed, |
| ... | @@ -1962,7 +1745,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { | ... | @@ -1962,7 +1745,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { |
| 1962 | try self.shared_objects.append(gpa, index); | 1745 | try self.shared_objects.append(gpa, index); |
| 1963 | 1746 | ||
| 1964 | const shared_object = self.file(index).?.shared_object; | 1747 | const shared_object = self.file(index).?.shared_object; |
| 1965 | try shared_object.parse(self); | 1748 | try shared_object.parse(self, handle); |
| 1966 | } | 1749 | } |
| 1967 | 1750 | ||
| 1968 | fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { | 1751 | fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { |
| ... | @@ -2084,7 +1867,7 @@ fn accessLibPath( | ... | @@ -2084,7 +1867,7 @@ fn accessLibPath( |
| 2084 | /// 4. Reset state of all resolved globals since we will redo this bit on the pruned set. | 1867 | /// 4. Reset state of all resolved globals since we will redo this bit on the pruned set. |
| 2085 | /// 5. Remove references to dead objects/shared objects | 1868 | /// 5. Remove references to dead objects/shared objects |
| 2086 | /// 6. Re-run symbol resolution on pruned objects and shared objects sets. | 1869 | /// 6. Re-run symbol resolution on pruned objects and shared objects sets. |
| 2087 | fn resolveSymbols(self: *Elf) void { | 1870 | pub fn resolveSymbols(self: *Elf) void { |
| 2088 | // Resolve symbols in the ZigObject. For now, we assume that it's always live. | 1871 | // Resolve symbols in the ZigObject. For now, we assume that it's always live. |
| 2089 | if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self); | 1872 | if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self); |
| 2090 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). | 1873 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). |
| ... | @@ -2135,7 +1918,7 @@ fn resolveSymbols(self: *Elf) void { | ... | @@ -2135,7 +1918,7 @@ fn resolveSymbols(self: *Elf) void { |
| 2135 | const cg = self.comdatGroup(cg_index); | 1918 | const cg = self.comdatGroup(cg_index); |
| 2136 | const cg_owner = self.comdatGroupOwner(cg.owner); | 1919 | const cg_owner = self.comdatGroupOwner(cg.owner); |
| 2137 | if (cg_owner.file != index) { | 1920 | if (cg_owner.file != index) { |
| 2138 | for (object.comdatGroupMembers(cg.shndx)) |shndx| { | 1921 | for (cg.comdatGroupMembers(self)) |shndx| { |
| 2139 | const atom_index = object.atoms.items[shndx]; | 1922 | const atom_index = object.atoms.items[shndx]; |
| 2140 | if (self.atom(atom_index)) |atom_ptr| { | 1923 | if (self.atom(atom_index)) |atom_ptr| { |
| 2141 | atom_ptr.flags.alive = false; | 1924 | atom_ptr.flags.alive = false; |
| ... | @@ -2168,7 +1951,7 @@ fn markLive(self: *Elf) void { | ... | @@ -2168,7 +1951,7 @@ fn markLive(self: *Elf) void { |
| 2168 | } | 1951 | } |
| 2169 | } | 1952 | } |
| 2170 | 1953 | ||
| 2171 | fn markEhFrameAtomsDead(self: *Elf) void { | 1954 | pub fn markEhFrameAtomsDead(self: *Elf) void { |
| 2172 | for (self.objects.items) |index| { | 1955 | for (self.objects.items) |index| { |
| 2173 | const file_ptr = self.file(index).?; | 1956 | const file_ptr = self.file(index).?; |
| 2174 | if (!file_ptr.isAlive()) continue; | 1957 | if (!file_ptr.isAlive()) continue; |
| ... | @@ -2234,15 +2017,6 @@ fn claimUnresolved(self: *Elf) void { | ... | @@ -2234,15 +2017,6 @@ fn claimUnresolved(self: *Elf) void { |
| 2234 | } | 2017 | } |
| 2235 | } | 2018 | } |
| 2236 | 2019 | ||
| 2237 | fn claimUnresolvedObject(self: *Elf) void { | ||
| 2238 | if (self.zigObjectPtr()) |zig_object| { | ||
| 2239 | zig_object.claimUnresolvedObject(self); | ||
| 2240 | } | ||
| 2241 | for (self.objects.items) |index| { | ||
| 2242 | self.file(index).?.object.claimUnresolvedObject(self); | ||
| 2243 | } | ||
| 2244 | } | ||
| 2245 | |||
| 2246 | /// In scanRelocs we will go over all live atoms and scan their relocs. | 2020 | /// In scanRelocs we will go over all live atoms and scan their relocs. |
| 2247 | /// This will help us work out what synthetics to emit, GOT indirection, etc. | 2021 | /// This will help us work out what synthetics to emit, GOT indirection, etc. |
| 2248 | /// This is also the point where we will report undefined symbols for any | 2022 | /// This is also the point where we will report undefined symbols for any |
| ... | @@ -2980,7 +2754,7 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) | ... | @@ -2980,7 +2754,7 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) |
| 2980 | } | 2754 | } |
| 2981 | } | 2755 | } |
| 2982 | 2756 | ||
| 2983 | fn writeShdrTable(self: *Elf) !void { | 2757 | pub fn writeShdrTable(self: *Elf) !void { |
| 2984 | const gpa = self.base.comp.gpa; | 2758 | const gpa = self.base.comp.gpa; |
| 2985 | const target = self.base.comp.root_mod.resolved_target.result; | 2759 | const target = self.base.comp.root_mod.resolved_target.result; |
| 2986 | const target_endian = target.cpu.arch.endian(); | 2760 | const target_endian = target.cpu.arch.endian(); |
| ... | @@ -3077,7 +2851,7 @@ fn writePhdrTable(self: *Elf) !void { | ... | @@ -3077,7 +2851,7 @@ fn writePhdrTable(self: *Elf) !void { |
| 3077 | } | 2851 | } |
| 3078 | } | 2852 | } |
| 3079 | 2853 | ||
| 3080 | fn writeElfHeader(self: *Elf) !void { | 2854 | pub fn writeElfHeader(self: *Elf) !void { |
| 3081 | const comp = self.base.comp; | 2855 | const comp = self.base.comp; |
| 3082 | if (comp.link_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable | 2856 | if (comp.link_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable |
| 3083 | 2857 | ||
| ... | @@ -3653,61 +3427,7 @@ fn initSyntheticSections(self: *Elf) !void { | ... | @@ -3653,61 +3427,7 @@ fn initSyntheticSections(self: *Elf) !void { |
| 3653 | try self.initShStrtab(); | 3427 | try self.initShStrtab(); |
| 3654 | } | 3428 | } |
| 3655 | 3429 | ||
| 3656 | fn initSectionsObject(self: *Elf) !void { | 3430 | pub fn initSymtab(self: *Elf) !void { |
| 3657 | const ptr_size = self.ptrWidthBytes(); | ||
| 3658 | |||
| 3659 | for (self.objects.items) |index| { | ||
| 3660 | const object = self.file(index).?.object; | ||
| 3661 | try object.initOutputSections(self); | ||
| 3662 | try object.initRelaSections(self); | ||
| 3663 | } | ||
| 3664 | |||
| 3665 | const needs_eh_frame = for (self.objects.items) |index| { | ||
| 3666 | if (self.file(index).?.object.cies.items.len > 0) break true; | ||
| 3667 | } else false; | ||
| 3668 | if (needs_eh_frame) { | ||
| 3669 | self.eh_frame_section_index = try self.addSection(.{ | ||
| 3670 | .name = ".eh_frame", | ||
| 3671 | .type = elf.SHT_PROGBITS, | ||
| 3672 | .flags = elf.SHF_ALLOC, | ||
| 3673 | .addralign = ptr_size, | ||
| 3674 | .offset = std.math.maxInt(u64), | ||
| 3675 | }); | ||
| 3676 | self.eh_frame_rela_section_index = try self.addRelaShdr(".rela.eh_frame", self.eh_frame_section_index.?); | ||
| 3677 | } | ||
| 3678 | |||
| 3679 | try self.initComdatGroups(); | ||
| 3680 | try self.initSymtab(); | ||
| 3681 | try self.initShStrtab(); | ||
| 3682 | } | ||
| 3683 | |||
| 3684 | fn initComdatGroups(self: *Elf) !void { | ||
| 3685 | const gpa = self.base.comp.gpa; | ||
| 3686 | |||
| 3687 | for (self.objects.items) |index| { | ||
| 3688 | const object = self.file(index).?.object; | ||
| 3689 | |||
| 3690 | for (object.comdat_groups.items) |cg_index| { | ||
| 3691 | const cg = self.comdatGroup(cg_index); | ||
| 3692 | const cg_owner = self.comdatGroupOwner(cg.owner); | ||
| 3693 | if (cg_owner.file != index) continue; | ||
| 3694 | |||
| 3695 | const cg_sec = try self.comdat_group_sections.addOne(gpa); | ||
| 3696 | cg_sec.* = .{ | ||
| 3697 | .shndx = try self.addSection(.{ | ||
| 3698 | .name = ".group", | ||
| 3699 | .type = elf.SHT_GROUP, | ||
| 3700 | .entsize = @sizeOf(u32), | ||
| 3701 | .addralign = @alignOf(u32), | ||
| 3702 | .offset = std.math.maxInt(u64), | ||
| 3703 | }), | ||
| 3704 | .cg_index = cg_index, | ||
| 3705 | }; | ||
| 3706 | } | ||
| 3707 | } | ||
| 3708 | } | ||
| 3709 | |||
| 3710 | fn initSymtab(self: *Elf) !void { | ||
| 3711 | const small_ptr = switch (self.ptr_width) { | 3431 | const small_ptr = switch (self.ptr_width) { |
| 3712 | .p32 => true, | 3432 | .p32 => true, |
| 3713 | .p64 => false, | 3433 | .p64 => false, |
| ... | @@ -3732,7 +3452,7 @@ fn initSymtab(self: *Elf) !void { | ... | @@ -3732,7 +3452,7 @@ fn initSymtab(self: *Elf) !void { |
| 3732 | } | 3452 | } |
| 3733 | } | 3453 | } |
| 3734 | 3454 | ||
| 3735 | fn initShStrtab(self: *Elf) !void { | 3455 | pub fn initShStrtab(self: *Elf) !void { |
| 3736 | if (self.shstrtab_section_index == null) { | 3456 | if (self.shstrtab_section_index == null) { |
| 3737 | self.shstrtab_section_index = try self.addSection(.{ | 3457 | self.shstrtab_section_index = try self.addSection(.{ |
| 3738 | .name = ".shstrtab", | 3458 | .name = ".shstrtab", |
| ... | @@ -4038,7 +3758,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 { | ... | @@ -4038,7 +3758,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 { |
| 4038 | } | 3758 | } |
| 4039 | } | 3759 | } |
| 4040 | 3760 | ||
| 4041 | fn sortShdrs(self: *Elf) !void { | 3761 | pub fn sortShdrs(self: *Elf) !void { |
| 4042 | const Entry = struct { | 3762 | const Entry = struct { |
| 4043 | shndx: u16, | 3763 | shndx: u16, |
| 4044 | 3764 | ||
| ... | @@ -4350,58 +4070,7 @@ fn updateSectionSizes(self: *Elf) !void { | ... | @@ -4350,58 +4070,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4350 | self.updateShStrtabSize(); | 4070 | self.updateShStrtabSize(); |
| 4351 | } | 4071 | } |
| 4352 | 4072 | ||
| 4353 | fn updateSectionSizesObject(self: *Elf) !void { | 4073 | pub fn updateShStrtabSize(self: *Elf) void { |
| 4354 | for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { | ||
| 4355 | const shdr = &self.shdrs.items[shndx]; | ||
| 4356 | for (atom_list.items) |atom_index| { | ||
| 4357 | const atom_ptr = self.atom(atom_index) orelse continue; | ||
| 4358 | if (!atom_ptr.flags.alive) continue; | ||
| 4359 | const offset = atom_ptr.alignment.forward(shdr.sh_size); | ||
| 4360 | const padding = offset - shdr.sh_size; | ||
| 4361 | atom_ptr.value = offset; | ||
| 4362 | shdr.sh_size += padding + atom_ptr.size; | ||
| 4363 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1)); | ||
| 4364 | } | ||
| 4365 | } | ||
| 4366 | |||
| 4367 | for (self.output_rela_sections.values()) |sec| { | ||
| 4368 | const shdr = &self.shdrs.items[sec.shndx]; | ||
| 4369 | for (sec.atom_list.items) |atom_index| { | ||
| 4370 | const atom_ptr = self.atom(atom_index) orelse continue; | ||
| 4371 | if (!atom_ptr.flags.alive) continue; | ||
| 4372 | const relocs = atom_ptr.relocs(self); | ||
| 4373 | shdr.sh_size += shdr.sh_entsize * relocs.len; | ||
| 4374 | } | ||
| 4375 | |||
| 4376 | if (shdr.sh_size == 0) shdr.sh_offset = 0; | ||
| 4377 | } | ||
| 4378 | |||
| 4379 | if (self.eh_frame_section_index) |index| { | ||
| 4380 | self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); | ||
| 4381 | } | ||
| 4382 | if (self.eh_frame_rela_section_index) |index| { | ||
| 4383 | const shdr = &self.shdrs.items[index]; | ||
| 4384 | shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize; | ||
| 4385 | } | ||
| 4386 | |||
| 4387 | try self.updateSymtabSize(); | ||
| 4388 | self.updateComdatGroupsSizes(); | ||
| 4389 | self.updateShStrtabSize(); | ||
| 4390 | } | ||
| 4391 | |||
| 4392 | fn updateComdatGroupsSizes(self: *Elf) void { | ||
| 4393 | for (self.comdat_group_sections.items) |cg| { | ||
| 4394 | const shdr = &self.shdrs.items[cg.shndx]; | ||
| 4395 | shdr.sh_size = cg.size(self); | ||
| 4396 | shdr.sh_link = self.symtab_section_index.?; | ||
| 4397 | |||
| 4398 | const sym = self.symbol(cg.symbol(self)); | ||
| 4399 | shdr.sh_info = sym.outputSymtabIndex(self) orelse | ||
| 4400 | self.sectionSymbolOutputSymtabIndex(sym.outputShndx().?); | ||
| 4401 | } | ||
| 4402 | } | ||
| 4403 | |||
| 4404 | fn updateShStrtabSize(self: *Elf) void { | ||
| 4405 | if (self.shstrtab_section_index) |index| { | 4074 | if (self.shstrtab_section_index) |index| { |
| 4406 | self.shdrs.items[index].sh_size = self.shstrtab.items.len; | 4075 | self.shdrs.items[index].sh_size = self.shstrtab.items.len; |
| 4407 | } | 4076 | } |
| ... | @@ -4486,7 +4155,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { | ... | @@ -4486,7 +4155,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { |
| 4486 | 4155 | ||
| 4487 | /// Allocates alloc sections and creates load segments for sections | 4156 | /// Allocates alloc sections and creates load segments for sections |
| 4488 | /// extracted from input object files. | 4157 | /// extracted from input object files. |
| 4489 | fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { | 4158 | pub fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4490 | // We use this struct to track maximum alignment of all TLS sections. | 4159 | // We use this struct to track maximum alignment of all TLS sections. |
| 4491 | // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold, | 4160 | // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold, |
| 4492 | // in-file offsets have to be aligned against the start of TLS program header. | 4161 | // in-file offsets have to be aligned against the start of TLS program header. |
| ... | @@ -4633,27 +4302,8 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { | ... | @@ -4633,27 +4302,8 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4633 | } | 4302 | } |
| 4634 | } | 4303 | } |
| 4635 | 4304 | ||
| 4636 | /// Allocates alloc sections when merging relocatable objects files together. | ||
| 4637 | fn allocateAllocSectionsObject(self: *Elf) !void { | ||
| 4638 | for (self.shdrs.items) |*shdr| { | ||
| 4639 | if (shdr.sh_type == elf.SHT_NULL) continue; | ||
| 4640 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; | ||
| 4641 | if (shdr.sh_type == elf.SHT_NOBITS) { | ||
| 4642 | shdr.sh_offset = 0; | ||
| 4643 | continue; | ||
| 4644 | } | ||
| 4645 | const needed_size = shdr.sh_size; | ||
| 4646 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { | ||
| 4647 | shdr.sh_size = 0; | ||
| 4648 | const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign); | ||
| 4649 | shdr.sh_offset = new_offset; | ||
| 4650 | shdr.sh_size = needed_size; | ||
| 4651 | } | ||
| 4652 | } | ||
| 4653 | } | ||
| 4654 | |||
| 4655 | /// Allocates non-alloc sections (debug info, symtabs, etc.). | 4305 | /// Allocates non-alloc sections (debug info, symtabs, etc.). |
| 4656 | fn allocateNonAllocSections(self: *Elf) !void { | 4306 | pub fn allocateNonAllocSections(self: *Elf) !void { |
| 4657 | for (self.shdrs.items, 0..) |*shdr, shndx| { | 4307 | for (self.shdrs.items, 0..) |*shdr, shndx| { |
| 4658 | if (shdr.sh_type == elf.SHT_NULL) continue; | 4308 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4659 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) continue; | 4309 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) continue; |
| ... | @@ -4752,7 +4402,7 @@ fn allocateSpecialPhdrs(self: *Elf) void { | ... | @@ -4752,7 +4402,7 @@ fn allocateSpecialPhdrs(self: *Elf) void { |
| 4752 | } | 4402 | } |
| 4753 | } | 4403 | } |
| 4754 | 4404 | ||
| 4755 | fn allocateAtoms(self: *Elf) void { | 4405 | pub fn allocateAtoms(self: *Elf) void { |
| 4756 | if (self.zigObjectPtr()) |zig_object| { | 4406 | if (self.zigObjectPtr()) |zig_object| { |
| 4757 | zig_object.allocateTlvAtoms(self); | 4407 | zig_object.allocateTlvAtoms(self); |
| 4758 | } | 4408 | } |
| ... | @@ -4849,76 +4499,7 @@ fn writeAtoms(self: *Elf) !void { | ... | @@ -4849,76 +4499,7 @@ fn writeAtoms(self: *Elf) !void { |
| 4849 | try self.reportUndefinedSymbols(&undefs); | 4499 | try self.reportUndefinedSymbols(&undefs); |
| 4850 | } | 4500 | } |
| 4851 | 4501 | ||
| 4852 | fn writeAtomsObject(self: *Elf) !void { | 4502 | pub fn updateSymtabSize(self: *Elf) !void { |
| 4853 | const gpa = self.base.comp.gpa; | ||
| 4854 | |||
| 4855 | // TODO iterate over `output_sections` directly | ||
| 4856 | for (self.shdrs.items, 0..) |shdr, shndx| { | ||
| 4857 | if (shdr.sh_type == elf.SHT_NULL) continue; | ||
| 4858 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | ||
| 4859 | |||
| 4860 | const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue; | ||
| 4861 | if (atom_list.items.len == 0) continue; | ||
| 4862 | |||
| 4863 | log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); | ||
| 4864 | |||
| 4865 | // TODO really, really handle debug section separately | ||
| 4866 | const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: { | ||
| 4867 | const zig_object = self.zigObjectPtr().?; | ||
| 4868 | if (shndx == self.debug_info_section_index.?) | ||
| 4869 | break :blk zig_object.debug_info_section_zig_size; | ||
| 4870 | if (shndx == self.debug_abbrev_section_index.?) | ||
| 4871 | break :blk zig_object.debug_abbrev_section_zig_size; | ||
| 4872 | if (shndx == self.debug_str_section_index.?) | ||
| 4873 | break :blk zig_object.debug_str_section_zig_size; | ||
| 4874 | if (shndx == self.debug_aranges_section_index.?) | ||
| 4875 | break :blk zig_object.debug_aranges_section_zig_size; | ||
| 4876 | if (shndx == self.debug_line_section_index.?) | ||
| 4877 | break :blk zig_object.debug_line_section_zig_size; | ||
| 4878 | unreachable; | ||
| 4879 | } else 0; | ||
| 4880 | const sh_offset = shdr.sh_offset + base_offset; | ||
| 4881 | const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; | ||
| 4882 | |||
| 4883 | const buffer = try gpa.alloc(u8, sh_size); | ||
| 4884 | defer gpa.free(buffer); | ||
| 4885 | const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and | ||
| 4886 | shdr.sh_flags & elf.SHF_EXECINSTR != 0) | ||
| 4887 | 0xcc // int3 | ||
| 4888 | else | ||
| 4889 | 0; | ||
| 4890 | @memset(buffer, padding_byte); | ||
| 4891 | |||
| 4892 | for (atom_list.items) |atom_index| { | ||
| 4893 | const atom_ptr = self.atom(atom_index).?; | ||
| 4894 | assert(atom_ptr.flags.alive); | ||
| 4895 | |||
| 4896 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse | ||
| 4897 | return error.Overflow; | ||
| 4898 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | ||
| 4899 | |||
| 4900 | log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{ | ||
| 4901 | atom_index, | ||
| 4902 | sh_offset + offset, | ||
| 4903 | sh_offset + offset + size, | ||
| 4904 | }); | ||
| 4905 | |||
| 4906 | // TODO decompress directly into provided buffer | ||
| 4907 | const out_code = buffer[offset..][0..size]; | ||
| 4908 | const in_code = switch (atom_ptr.file(self).?) { | ||
| 4909 | .object => |x| try x.codeDecompressAlloc(self, atom_index), | ||
| 4910 | .zig_object => |x| try x.codeAlloc(self, atom_index), | ||
| 4911 | else => unreachable, | ||
| 4912 | }; | ||
| 4913 | defer gpa.free(in_code); | ||
| 4914 | @memcpy(out_code, in_code); | ||
| 4915 | } | ||
| 4916 | |||
| 4917 | try self.base.file.?.pwriteAll(buffer, sh_offset); | ||
| 4918 | } | ||
| 4919 | } | ||
| 4920 | |||
| 4921 | fn updateSymtabSize(self: *Elf) !void { | ||
| 4922 | var nlocals: u32 = 0; | 4503 | var nlocals: u32 = 0; |
| 4923 | var nglobals: u32 = 0; | 4504 | var nglobals: u32 = 0; |
| 4924 | var strsize: u32 = 0; | 4505 | var strsize: u32 = 0; |
| ... | @@ -5136,94 +4717,7 @@ fn writeSyntheticSections(self: *Elf) !void { | ... | @@ -5136,94 +4717,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 5136 | try self.writeShStrtab(); | 4717 | try self.writeShStrtab(); |
| 5137 | } | 4718 | } |
| 5138 | 4719 | ||
| 5139 | fn writeSyntheticSectionsObject(self: *Elf) !void { | 4720 | pub fn writeShStrtab(self: *Elf) !void { |
| 5140 | const gpa = self.base.comp.gpa; | ||
| 5141 | |||
| 5142 | for (self.output_rela_sections.values()) |sec| { | ||
| 5143 | if (sec.atom_list.items.len == 0) continue; | ||
| 5144 | |||
| 5145 | const shdr = self.shdrs.items[sec.shndx]; | ||
| 5146 | |||
| 5147 | const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse | ||
| 5148 | return error.Overflow; | ||
| 5149 | var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs); | ||
| 5150 | defer relocs.deinit(); | ||
| 5151 | |||
| 5152 | for (sec.atom_list.items) |atom_index| { | ||
| 5153 | const atom_ptr = self.atom(atom_index) orelse continue; | ||
| 5154 | if (!atom_ptr.flags.alive) continue; | ||
| 5155 | try atom_ptr.writeRelocs(self, &relocs); | ||
| 5156 | } | ||
| 5157 | assert(relocs.items.len == num_relocs); | ||
| 5158 | |||
| 5159 | const SortRelocs = struct { | ||
| 5160 | pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { | ||
| 5161 | _ = ctx; | ||
| 5162 | return lhs.r_offset < rhs.r_offset; | ||
| 5163 | } | ||
| 5164 | }; | ||
| 5165 | |||
| 5166 | mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan); | ||
| 5167 | |||
| 5168 | log.debug("writing {s} from 0x{x} to 0x{x}", .{ | ||
| 5169 | self.getShString(shdr.sh_name), | ||
| 5170 | shdr.sh_offset, | ||
| 5171 | shdr.sh_offset + shdr.sh_size, | ||
| 5172 | }); | ||
| 5173 | |||
| 5174 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); | ||
| 5175 | } | ||
| 5176 | |||
| 5177 | if (self.eh_frame_section_index) |shndx| { | ||
| 5178 | const shdr = self.shdrs.items[shndx]; | ||
| 5179 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 5180 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); | ||
| 5181 | defer buffer.deinit(); | ||
| 5182 | try eh_frame.writeEhFrameObject(self, buffer.writer()); | ||
| 5183 | log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ | ||
| 5184 | shdr.sh_offset, | ||
| 5185 | shdr.sh_offset + shdr.sh_size, | ||
| 5186 | }); | ||
| 5187 | assert(buffer.items.len == sh_size); | ||
| 5188 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 5189 | } | ||
| 5190 | if (self.eh_frame_rela_section_index) |shndx| { | ||
| 5191 | const shdr = self.shdrs.items[shndx]; | ||
| 5192 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 5193 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); | ||
| 5194 | defer buffer.deinit(); | ||
| 5195 | try eh_frame.writeEhFrameRelocs(self, buffer.writer()); | ||
| 5196 | assert(buffer.items.len == sh_size); | ||
| 5197 | log.debug("writing .rela.eh_frame from 0x{x} to 0x{x}", .{ | ||
| 5198 | shdr.sh_offset, | ||
| 5199 | shdr.sh_offset + shdr.sh_size, | ||
| 5200 | }); | ||
| 5201 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 5202 | } | ||
| 5203 | |||
| 5204 | try self.writeComdatGroups(); | ||
| 5205 | try self.writeSymtab(); | ||
| 5206 | try self.writeShStrtab(); | ||
| 5207 | } | ||
| 5208 | |||
| 5209 | fn writeComdatGroups(self: *Elf) !void { | ||
| 5210 | const gpa = self.base.comp.gpa; | ||
| 5211 | for (self.comdat_group_sections.items) |cgs| { | ||
| 5212 | const shdr = self.shdrs.items[cgs.shndx]; | ||
| 5213 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 5214 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); | ||
| 5215 | defer buffer.deinit(); | ||
| 5216 | try cgs.write(self, buffer.writer()); | ||
| 5217 | assert(buffer.items.len == sh_size); | ||
| 5218 | log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{ | ||
| 5219 | shdr.sh_offset, | ||
| 5220 | shdr.sh_offset + shdr.sh_size, | ||
| 5221 | }); | ||
| 5222 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 5223 | } | ||
| 5224 | } | ||
| 5225 | |||
| 5226 | fn writeShStrtab(self: *Elf) !void { | ||
| 5227 | if (self.shstrtab_section_index) |index| { | 4721 | if (self.shstrtab_section_index) |index| { |
| 5228 | const shdr = self.shdrs.items[index]; | 4722 | const shdr = self.shdrs.items[index]; |
| 5229 | log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size }); | 4723 | log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size }); |
| ... | @@ -5231,7 +4725,7 @@ fn writeShStrtab(self: *Elf) !void { | ... | @@ -5231,7 +4725,7 @@ fn writeShStrtab(self: *Elf) !void { |
| 5231 | } | 4725 | } |
| 5232 | } | 4726 | } |
| 5233 | 4727 | ||
| 5234 | fn writeSymtab(self: *Elf) !void { | 4728 | pub fn writeSymtab(self: *Elf) !void { |
| 5235 | const target = self.base.comp.root_mod.resolved_target.result; | 4729 | const target = self.base.comp.root_mod.resolved_target.result; |
| 5236 | const gpa = self.base.comp.gpa; | 4730 | const gpa = self.base.comp.gpa; |
| 5237 | const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; | 4731 | const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; |
| ... | @@ -5362,7 +4856,7 @@ pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { | ... | @@ -5362,7 +4856,7 @@ pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { |
| 5362 | } | 4856 | } |
| 5363 | 4857 | ||
| 5364 | /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF. | 4858 | /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF. |
| 5365 | fn ptrWidthBytes(self: Elf) u8 { | 4859 | pub fn ptrWidthBytes(self: Elf) u8 { |
| 5366 | return switch (self.ptr_width) { | 4860 | return switch (self.ptr_width) { |
| 5367 | .p32 => 4, | 4861 | .p32 => 4, |
| 5368 | .p64 => 8, | 4862 | .p64 => 8, |
| ... | @@ -5708,7 +5202,7 @@ fn addPhdr(self: *Elf, opts: struct { | ... | @@ -5708,7 +5202,7 @@ fn addPhdr(self: *Elf, opts: struct { |
| 5708 | return index; | 5202 | return index; |
| 5709 | } | 5203 | } |
| 5710 | 5204 | ||
| 5711 | fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 { | 5205 | pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 { |
| 5712 | const entsize: u64 = switch (self.ptr_width) { | 5206 | const entsize: u64 = switch (self.ptr_width) { |
| 5713 | .p32 => @sizeOf(elf.Elf32_Rela), | 5207 | .p32 => @sizeOf(elf.Elf32_Rela), |
| 5714 | .p64 => @sizeOf(elf.Elf64_Rela), | 5208 | .p64 => @sizeOf(elf.Elf64_Rela), |
| ... | @@ -5862,6 +5356,19 @@ pub fn file(self: *Elf, index: File.Index) ?File { | ... | @@ -5862,6 +5356,19 @@ pub fn file(self: *Elf, index: File.Index) ?File { |
| 5862 | }; | 5356 | }; |
| 5863 | } | 5357 | } |
| 5864 | 5358 | ||
| 5359 | pub fn addFileHandle(self: *Elf, handle: std.fs.File) !File.HandleIndex { | ||
| 5360 | const gpa = self.base.comp.gpa; | ||
| 5361 | const index: File.HandleIndex = @intCast(self.file_handles.items.len); | ||
| 5362 | const fh = try self.file_handles.addOne(gpa); | ||
| 5363 | fh.* = handle; | ||
| 5364 | return index; | ||
| 5365 | } | ||
| 5366 | |||
| 5367 | pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle { | ||
| 5368 | assert(index < self.file_handles.items.len); | ||
| 5369 | return self.file_handles.items[index]; | ||
| 5370 | } | ||
| 5371 | |||
| 5865 | /// Returns pointer-to-symbol described at sym_index. | 5372 | /// Returns pointer-to-symbol described at sym_index. |
| 5866 | pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { | 5373 | pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { |
| 5867 | return &self.symbols.items[sym_index]; | 5374 | return &self.symbols.items[sym_index]; |
| ... | @@ -6322,7 +5829,7 @@ fn formatPhdr( | ... | @@ -6322,7 +5829,7 @@ fn formatPhdr( |
| 6322 | }); | 5829 | }); |
| 6323 | } | 5830 | } |
| 6324 | 5831 | ||
| 6325 | fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { | 5832 | pub fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { |
| 6326 | return .{ .data = self }; | 5833 | return .{ .data = self }; |
| 6327 | } | 5834 | } |
| 6328 | 5835 | ||
| ... | @@ -6395,6 +5902,15 @@ fn fmtDumpState( | ... | @@ -6395,6 +5902,15 @@ fn fmtDumpState( |
| 6395 | } | 5902 | } |
| 6396 | } | 5903 | } |
| 6397 | 5904 | ||
| 5905 | /// Caller owns the memory. | ||
| 5906 | pub fn preadAllAlloc(allocator: Allocator, handle: std.fs.File, offset: u64, size: u64) ![]u8 { | ||
| 5907 | const buffer = try allocator.alloc(u8, math.cast(usize, size) orelse return error.Overflow); | ||
| 5908 | errdefer allocator.free(buffer); | ||
| 5909 | const amt = try handle.preadAll(buffer, offset); | ||
| 5910 | if (amt != size) return error.InputOutput; | ||
| 5911 | return buffer; | ||
| 5912 | } | ||
| 5913 | |||
| 6398 | /// Binary search | 5914 | /// Binary search |
| 6399 | pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize { | 5915 | pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize { |
| 6400 | if (!@hasDecl(@TypeOf(predicate), "predicate")) | 5916 | if (!@hasDecl(@TypeOf(predicate), "predicate")) |
| ... | @@ -6441,12 +5957,22 @@ pub const base_tag: link.File.Tag = .elf; | ... | @@ -6441,12 +5957,22 @@ pub const base_tag: link.File.Tag = .elf; |
| 6441 | 5957 | ||
| 6442 | const ComdatGroupOwner = struct { | 5958 | const ComdatGroupOwner = struct { |
| 6443 | file: File.Index = 0, | 5959 | file: File.Index = 0, |
| 5960 | |||
| 6444 | const Index = u32; | 5961 | const Index = u32; |
| 6445 | }; | 5962 | }; |
| 6446 | 5963 | ||
| 6447 | pub const ComdatGroup = struct { | 5964 | pub const ComdatGroup = struct { |
| 6448 | owner: ComdatGroupOwner.Index, | 5965 | owner: ComdatGroupOwner.Index, |
| 6449 | shndx: u16, | 5966 | file: File.Index, |
| 5967 | shndx: u32, | ||
| 5968 | members_start: u32, | ||
| 5969 | members_len: u32, | ||
| 5970 | |||
| 5971 | pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 { | ||
| 5972 | const object = elf_file.file(cg.file).?.object; | ||
| 5973 | return object.comdat_group_data.items[cg.members_start..][0..cg.members_len]; | ||
| 5974 | } | ||
| 5975 | |||
| 6450 | pub const Index = u32; | 5976 | pub const Index = u32; |
| 6451 | }; | 5977 | }; |
| 6452 | 5978 | ||
| ... | @@ -6542,6 +6068,7 @@ const glibc = @import("../glibc.zig"); | ... | @@ -6542,6 +6068,7 @@ const glibc = @import("../glibc.zig"); |
| 6542 | const link = @import("../link.zig"); | 6068 | const link = @import("../link.zig"); |
| 6543 | const lldMain = @import("../main.zig").lldMain; | 6069 | const lldMain = @import("../main.zig").lldMain; |
| 6544 | const musl = @import("../musl.zig"); | 6070 | const musl = @import("../musl.zig"); |
| 6071 | const relocatable = @import("Elf/relocatable.zig"); | ||
| 6545 | const target_util = @import("../target.zig"); | 6072 | const target_util = @import("../target.zig"); |
| 6546 | const trace = @import("../tracy.zig").trace; | 6073 | const trace = @import("../tracy.zig").trace; |
| 6547 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); | 6074 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); |
src/link/Elf/Archive.zig+33-29| ... | @@ -1,8 +1,5 @@ | ... | @@ -1,8 +1,5 @@ |
| 1 | path: []const u8, | ||
| 2 | data: []const u8, | ||
| 3 | |||
| 4 | objects: std.ArrayListUnmanaged(Object) = .{}, | 1 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 5 | strtab: []const u8 = &[0]u8{}, | 2 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 6 | 3 | ||
| 7 | pub fn isArchive(path: []const u8) !bool { | 4 | pub fn isArchive(path: []const u8) !bool { |
| 8 | const file = try std.fs.cwd().openFile(path, .{}); | 5 | const file = try std.fs.cwd().openFile(path, .{}); |
| ... | @@ -14,68 +11,75 @@ pub fn isArchive(path: []const u8) !bool { | ... | @@ -14,68 +11,75 @@ pub fn isArchive(path: []const u8) !bool { |
| 14 | } | 11 | } |
| 15 | 12 | ||
| 16 | pub fn deinit(self: *Archive, allocator: Allocator) void { | 13 | pub fn deinit(self: *Archive, allocator: Allocator) void { |
| 17 | allocator.free(self.path); | ||
| 18 | allocator.free(self.data); | ||
| 19 | self.objects.deinit(allocator); | 14 | self.objects.deinit(allocator); |
| 15 | self.strtab.deinit(allocator); | ||
| 20 | } | 16 | } |
| 21 | 17 | ||
| 22 | pub fn parse(self: *Archive, elf_file: *Elf) !void { | 18 | pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: File.HandleIndex) !void { |
| 23 | const comp = elf_file.base.comp; | 19 | const comp = elf_file.base.comp; |
| 24 | const gpa = comp.gpa; | 20 | const gpa = comp.gpa; |
| 21 | const handle = elf_file.fileHandle(handle_index); | ||
| 22 | const size = (try handle.stat()).size; | ||
| 25 | 23 | ||
| 26 | var stream = std.io.fixedBufferStream(self.data); | 24 | var pos: usize = elf.ARMAG.len; |
| 27 | const reader = stream.reader(); | ||
| 28 | _ = try reader.readBytesNoEof(elf.ARMAG.len); | ||
| 29 | |||
| 30 | while (true) { | 25 | while (true) { |
| 31 | if (stream.pos >= self.data.len) break; | 26 | if (pos >= size) break; |
| 32 | if (!mem.isAligned(stream.pos, 2)) stream.pos += 1; | 27 | if (!mem.isAligned(pos, 2)) pos += 1; |
| 33 | 28 | ||
| 34 | const hdr = try reader.readStruct(elf.ar_hdr); | 29 | var hdr_buffer: [@sizeOf(elf.ar_hdr)]u8 = undefined; |
| 30 | { | ||
| 31 | const amt = try handle.preadAll(&hdr_buffer, pos); | ||
| 32 | if (amt != @sizeOf(elf.ar_hdr)) return error.InputOutput; | ||
| 33 | } | ||
| 34 | const hdr = @as(*align(1) const elf.ar_hdr, @ptrCast(&hdr_buffer)).*; | ||
| 35 | pos += @sizeOf(elf.ar_hdr); | ||
| 35 | 36 | ||
| 36 | if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { | 37 | if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { |
| 37 | try elf_file.reportParseError(self.path, "invalid archive header delimiter: {s}", .{ | 38 | try elf_file.reportParseError(path, "invalid archive header delimiter: {s}", .{ |
| 38 | std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), | 39 | std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), |
| 39 | }); | 40 | }); |
| 40 | return error.MalformedArchive; | 41 | return error.MalformedArchive; |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | const size = try hdr.size(); | 44 | const obj_size = try hdr.size(); |
| 44 | defer { | 45 | defer pos += obj_size; |
| 45 | _ = stream.seekBy(size) catch {}; | ||
| 46 | } | ||
| 47 | 46 | ||
| 48 | if (hdr.isSymtab() or hdr.isSymtab64()) continue; | 47 | if (hdr.isSymtab() or hdr.isSymtab64()) continue; |
| 49 | if (hdr.isStrtab()) { | 48 | if (hdr.isStrtab()) { |
| 50 | self.strtab = self.data[stream.pos..][0..size]; | 49 | try self.strtab.resize(gpa, obj_size); |
| 50 | const amt = try handle.preadAll(self.strtab.items, pos); | ||
| 51 | if (amt != obj_size) return error.InputOutput; | ||
| 51 | continue; | 52 | continue; |
| 52 | } | 53 | } |
| 53 | if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; | 54 | if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; |
| 54 | 55 | ||
| 55 | const name = if (hdr.name()) |name| | 56 | const name = if (hdr.name()) |name| |
| 56 | try gpa.dupe(u8, name) | 57 | name |
| 57 | else if (try hdr.nameOffset()) |off| | 58 | else if (try hdr.nameOffset()) |off| |
| 58 | try gpa.dupe(u8, self.getString(off)) | 59 | self.getString(off) |
| 59 | else | 60 | else |
| 60 | unreachable; | 61 | unreachable; |
| 61 | 62 | ||
| 62 | const object = Object{ | 63 | const object = Object{ |
| 63 | .archive = try gpa.dupe(u8, self.path), | 64 | .archive = .{ |
| 64 | .path = name, | 65 | .path = try gpa.dupe(u8, path), |
| 65 | .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]), | 66 | .offset = pos, |
| 67 | }, | ||
| 68 | .path = try gpa.dupe(u8, name), | ||
| 69 | .file_handle = handle_index, | ||
| 66 | .index = undefined, | 70 | .index = undefined, |
| 67 | .alive = false, | 71 | .alive = false, |
| 68 | }; | 72 | }; |
| 69 | 73 | ||
| 70 | log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path }); | 74 | log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path }); |
| 71 | 75 | ||
| 72 | try self.objects.append(gpa, object); | 76 | try self.objects.append(gpa, object); |
| 73 | } | 77 | } |
| 74 | } | 78 | } |
| 75 | 79 | ||
| 76 | fn getString(self: Archive, off: u32) []const u8 { | 80 | fn getString(self: Archive, off: u32) []const u8 { |
| 77 | assert(off < self.strtab.len); | 81 | assert(off < self.strtab.items.len); |
| 78 | const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.ptr + off)), 0); | 82 | const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 79 | return name[0 .. name.len - 1]; | 83 | return name[0 .. name.len - 1]; |
| 80 | } | 84 | } |
| 81 | 85 | ||
| ... | @@ -86,7 +90,7 @@ pub fn setArHdr(opts: struct { | ... | @@ -86,7 +90,7 @@ pub fn setArHdr(opts: struct { |
| 86 | name: []const u8, | 90 | name: []const u8, |
| 87 | name_off: u32, | 91 | name_off: u32, |
| 88 | }, | 92 | }, |
| 89 | size: u32, | 93 | size: usize, |
| 90 | }) elf.ar_hdr { | 94 | }) elf.ar_hdr { |
| 91 | var hdr: elf.ar_hdr = .{ | 95 | var hdr: elf.ar_hdr = .{ |
| 92 | .ar_name = undefined, | 96 | .ar_name = undefined, |
src/link/Elf/Atom.zig+8-2| ... | @@ -22,6 +22,12 @@ output_section_index: u16 = 0, | ... | @@ -22,6 +22,12 @@ output_section_index: u16 = 0, |
| 22 | /// Index of the input section containing this atom's relocs. | 22 | /// Index of the input section containing this atom's relocs. |
| 23 | relocs_section_index: u32 = 0, | 23 | relocs_section_index: u32 = 0, |
| 24 | 24 | ||
| 25 | /// Start index of the relocations belonging to this atom. | ||
| 26 | rel_index: u32 = 0, | ||
| 27 | |||
| 28 | /// Number of relocations belonging to this atom. | ||
| 29 | rel_num: u32 = 0, | ||
| 30 | |||
| 25 | /// Index of this atom in the linker's atoms table. | 31 | /// Index of this atom in the linker's atoms table. |
| 26 | atom_index: Index = 0, | 32 | atom_index: Index = 0, |
| 27 | 33 | ||
| ... | @@ -52,7 +58,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { | ... | @@ -52,7 +58,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { |
| 52 | return elf_file.file(self.file_index); | 58 | return elf_file.file(self.file_index); |
| 53 | } | 59 | } |
| 54 | 60 | ||
| 55 | pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr { | 61 | pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { |
| 56 | return switch (self.file(elf_file).?) { | 62 | return switch (self.file(elf_file).?) { |
| 57 | .object => |x| x.shdrs.items[self.input_section_index], | 63 | .object => |x| x.shdrs.items[self.input_section_index], |
| 58 | .zig_object => |x| x.inputShdr(self.atom_index, elf_file), | 64 | .zig_object => |x| x.inputShdr(self.atom_index, elf_file), |
| ... | @@ -289,7 +295,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela { | ... | @@ -289,7 +295,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela { |
| 289 | const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; | 295 | const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; |
| 290 | return switch (self.file(elf_file).?) { | 296 | return switch (self.file(elf_file).?) { |
| 291 | .zig_object => |x| x.relocs.items[shndx].items, | 297 | .zig_object => |x| x.relocs.items[shndx].items, |
| 292 | .object => |x| x.getRelocs(shndx), | 298 | .object => |x| x.relocs.items[self.rel_index..][0..self.rel_num], |
| 293 | else => unreachable, | 299 | else => unreachable, |
| 294 | }; | 300 | }; |
| 295 | } | 301 | } |
src/link/Elf/Object.zig+143-126| ... | @@ -1,10 +1,10 @@ | ... | @@ -1,10 +1,10 @@ |
| 1 | archive: ?[]const u8 = null, | 1 | archive: ?InArchive = null, |
| 2 | path: []const u8, | 2 | path: []const u8, |
| 3 | data: []const u8, | 3 | file_handle: File.HandleIndex, |
| 4 | index: File.Index, | 4 | index: File.Index, |
| 5 | 5 | ||
| 6 | header: ?elf.Elf64_Ehdr = null, | 6 | header: ?elf.Elf64_Ehdr = null, |
| 7 | shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, | 7 | shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, |
| 8 | 8 | ||
| 9 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | 9 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| ... | @@ -12,9 +12,12 @@ first_global: ?Symbol.Index = null, | ... | @@ -12,9 +12,12 @@ first_global: ?Symbol.Index = null, |
| 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 14 | comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, | 14 | comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, |
| 15 | comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, | ||
| 16 | relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | ||
| 15 | 17 | ||
| 16 | fdes: std.ArrayListUnmanaged(Fde) = .{}, | 18 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 17 | cies: std.ArrayListUnmanaged(Cie) = .{}, | 19 | cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 20 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, | ||
| 18 | 21 | ||
| 19 | alive: bool = true, | 22 | alive: bool = true, |
| 20 | num_dynrelocs: u32 = 0, | 23 | num_dynrelocs: u32 = 0, |
| ... | @@ -35,24 +38,44 @@ pub fn isObject(path: []const u8) !bool { | ... | @@ -35,24 +38,44 @@ pub fn isObject(path: []const u8) !bool { |
| 35 | } | 38 | } |
| 36 | 39 | ||
| 37 | pub fn deinit(self: *Object, allocator: Allocator) void { | 40 | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 38 | if (self.archive) |path| allocator.free(path); | 41 | if (self.archive) |*ar| allocator.free(ar.path); |
| 39 | allocator.free(self.path); | 42 | allocator.free(self.path); |
| 40 | allocator.free(self.data); | ||
| 41 | self.shdrs.deinit(allocator); | 43 | self.shdrs.deinit(allocator); |
| 42 | self.symtab.deinit(allocator); | 44 | self.symtab.deinit(allocator); |
| 43 | self.strtab.deinit(allocator); | 45 | self.strtab.deinit(allocator); |
| 44 | self.symbols.deinit(allocator); | 46 | self.symbols.deinit(allocator); |
| 45 | self.atoms.deinit(allocator); | 47 | self.atoms.deinit(allocator); |
| 46 | self.comdat_groups.deinit(allocator); | 48 | self.comdat_groups.deinit(allocator); |
| 49 | self.comdat_group_data.deinit(allocator); | ||
| 50 | self.relocs.deinit(allocator); | ||
| 47 | self.fdes.deinit(allocator); | 51 | self.fdes.deinit(allocator); |
| 48 | self.cies.deinit(allocator); | 52 | self.cies.deinit(allocator); |
| 53 | self.eh_frame_data.deinit(allocator); | ||
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | pub fn parse(self: *Object, elf_file: *Elf) !void { | 56 | pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 52 | var stream = std.io.fixedBufferStream(self.data); | 57 | const gpa = elf_file.base.comp.gpa; |
| 53 | const reader = stream.reader(); | 58 | const handle = elf_file.fileHandle(self.file_handle); |
| 54 | 59 | ||
| 55 | self.header = try reader.readStruct(elf.Elf64_Ehdr); | 60 | try self.parseCommon(gpa, handle, elf_file); |
| 61 | try self.initAtoms(gpa, handle, elf_file); | ||
| 62 | try self.initSymtab(gpa, elf_file); | ||
| 63 | |||
| 64 | for (self.shdrs.items, 0..) |shdr, i| { | ||
| 65 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; | ||
| 66 | if (!atom.flags.alive) continue; | ||
| 67 | if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) | ||
| 68 | try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { | ||
| 73 | const offset = if (self.archive) |ar| ar.offset else 0; | ||
| 74 | const file_size = (try handle.stat()).size; | ||
| 75 | |||
| 76 | const header_buffer = try Elf.preadAllAlloc(allocator, handle, offset, @sizeOf(elf.Elf64_Ehdr)); | ||
| 77 | defer allocator.free(header_buffer); | ||
| 78 | self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; | ||
| 56 | 79 | ||
| 57 | const target = elf_file.base.comp.root_mod.resolved_target.result; | 80 | const target = elf_file.base.comp.root_mod.resolved_target.result; |
| 58 | if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { | 81 | if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { |
| ... | @@ -66,12 +89,10 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -66,12 +89,10 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 66 | 89 | ||
| 67 | if (self.header.?.e_shnum == 0) return; | 90 | if (self.header.?.e_shnum == 0) return; |
| 68 | 91 | ||
| 69 | const comp = elf_file.base.comp; | 92 | const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; |
| 70 | const gpa = comp.gpa; | 93 | const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; |
| 71 | 94 | const shsize = shnum * @sizeOf(elf.Elf64_Shdr); | |
| 72 | if (self.data.len < self.header.?.e_shoff or | 95 | if (file_size < offset + shoff or file_size < offset + shoff + shsize) { |
| 73 | self.data.len < self.header.?.e_shoff + @as(u64, @intCast(self.header.?.e_shnum)) * @sizeOf(elf.Elf64_Shdr)) | ||
| 74 | { | ||
| 75 | try elf_file.reportParseError2( | 96 | try elf_file.reportParseError2( |
| 76 | self.index, | 97 | self.index, |
| 77 | "corrupt header: section header table extends past the end of file", | 98 | "corrupt header: section header table extends past the end of file", |
| ... | @@ -80,31 +101,29 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -80,31 +101,29 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 80 | return error.MalformedObject; | 101 | return error.MalformedObject; |
| 81 | } | 102 | } |
| 82 | 103 | ||
| 83 | const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; | 104 | const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize); |
| 84 | const shdrs = @as( | 105 | defer allocator.free(shdrs_buffer); |
| 85 | [*]align(1) const elf.Elf64_Shdr, | 106 | const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; |
| 86 | @ptrCast(self.data.ptr + shoff), | 107 | try self.shdrs.appendUnalignedSlice(allocator, shdrs); |
| 87 | )[0..self.header.?.e_shnum]; | ||
| 88 | try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len); | ||
| 89 | 108 | ||
| 90 | for (shdrs) |shdr| { | 109 | for (self.shdrs.items) |shdr| { |
| 91 | if (shdr.sh_type != elf.SHT_NOBITS) { | 110 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 92 | if (self.data.len < shdr.sh_offset or self.data.len < shdr.sh_offset + shdr.sh_size) { | 111 | if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) { |
| 93 | try elf_file.reportParseError2(self.index, "corrupt section: extends past the end of file", .{}); | 112 | try elf_file.reportParseError2(self.index, "corrupt section: extends past the end of file", .{}); |
| 94 | return error.MalformedObject; | 113 | return error.MalformedObject; |
| 95 | } | 114 | } |
| 96 | } | 115 | } |
| 97 | self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); | ||
| 98 | } | 116 | } |
| 99 | 117 | ||
| 100 | const shstrtab = self.shdrContents(self.header.?.e_shstrndx); | 118 | const shstrtab = try self.preadShdrContentsAlloc(allocator, handle, self.header.?.e_shstrndx); |
| 101 | for (shdrs) |shdr| { | 119 | defer allocator.free(shstrtab); |
| 120 | for (self.shdrs.items) |shdr| { | ||
| 102 | if (shdr.sh_name >= shstrtab.len) { | 121 | if (shdr.sh_name >= shstrtab.len) { |
| 103 | try elf_file.reportParseError2(self.index, "corrupt section name offset", .{}); | 122 | try elf_file.reportParseError2(self.index, "corrupt section name offset", .{}); |
| 104 | return error.MalformedObject; | 123 | return error.MalformedObject; |
| 105 | } | 124 | } |
| 106 | } | 125 | } |
| 107 | try self.strtab.appendSlice(gpa, shstrtab); | 126 | try self.strtab.appendSlice(allocator, shstrtab); |
| 108 | 127 | ||
| 109 | const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { | 128 | const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { |
| 110 | elf.SHT_SYMTAB => break @as(u16, @intCast(i)), | 129 | elf.SHT_SYMTAB => break @as(u16, @intCast(i)), |
| ... | @@ -112,10 +131,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -112,10 +131,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 112 | } else null; | 131 | } else null; |
| 113 | 132 | ||
| 114 | if (symtab_index) |index| { | 133 | if (symtab_index) |index| { |
| 115 | const shdr = shdrs[index]; | 134 | const shdr = self.shdrs.items[index]; |
| 116 | self.first_global = shdr.sh_info; | 135 | self.first_global = shdr.sh_info; |
| 117 | 136 | ||
| 118 | const raw_symtab = self.shdrContents(index); | 137 | const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index); |
| 138 | defer allocator.free(raw_symtab); | ||
| 119 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { | 139 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { |
| 120 | try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{}); | 140 | try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{}); |
| 121 | return error.MalformedObject; | 141 | return error.MalformedObject; |
| ... | @@ -123,9 +143,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -123,9 +143,11 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 123 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; | 143 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; |
| 124 | 144 | ||
| 125 | const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); | 145 | const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); |
| 126 | try self.strtab.appendSlice(gpa, self.shdrContents(@as(u16, @intCast(shdr.sh_link)))); | 146 | const strtab = try self.preadShdrContentsAlloc(allocator, handle, shdr.sh_link); |
| 147 | defer allocator.free(strtab); | ||
| 148 | try self.strtab.appendSlice(allocator, strtab); | ||
| 127 | 149 | ||
| 128 | try self.symtab.ensureUnusedCapacity(gpa, symtab.len); | 150 | try self.symtab.ensureUnusedCapacity(allocator, symtab.len); |
| 129 | for (symtab) |sym| { | 151 | for (symtab) |sym| { |
| 130 | const out_sym = self.symtab.addOneAssumeCapacity(); | 152 | const out_sym = self.symtab.addOneAssumeCapacity(); |
| 131 | out_sym.* = sym; | 153 | out_sym.* = sym; |
| ... | @@ -137,23 +159,9 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { | ... | @@ -137,23 +159,9 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { |
| 137 | } | 159 | } |
| 138 | } | 160 | } |
| 139 | 161 | ||
| 140 | pub fn init(self: *Object, elf_file: *Elf) !void { | 162 | fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void { |
| 141 | try self.initAtoms(elf_file); | ||
| 142 | try self.initSymtab(elf_file); | ||
| 143 | |||
| 144 | for (self.shdrs.items, 0..) |shdr, i| { | ||
| 145 | const atom = elf_file.atom(self.atoms.items[i]) orelse continue; | ||
| 146 | if (!atom.flags.alive) continue; | ||
| 147 | if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) | ||
| 148 | try self.parseEhFrame(@as(u16, @intCast(i)), elf_file); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | fn initAtoms(self: *Object, elf_file: *Elf) !void { | ||
| 153 | const comp = elf_file.base.comp; | ||
| 154 | const gpa = comp.gpa; | ||
| 155 | const shdrs = self.shdrs.items; | 163 | const shdrs = self.shdrs.items; |
| 156 | try self.atoms.resize(gpa, shdrs.len); | 164 | try self.atoms.resize(allocator, shdrs.len); |
| 157 | @memset(self.atoms.items, 0); | 165 | @memset(self.atoms.items, 0); |
| 158 | 166 | ||
| 159 | for (shdrs, 0..) |shdr, i| { | 167 | for (shdrs, 0..) |shdr, i| { |
| ... | @@ -177,8 +185,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { | ... | @@ -177,8 +185,9 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 177 | break :blk self.getString(group_info_sym.st_name); | 185 | break :blk self.getString(group_info_sym.st_name); |
| 178 | }; | 186 | }; |
| 179 | 187 | ||
| 180 | const shndx = @as(u16, @intCast(i)); | 188 | const shndx = @as(u32, @intCast(i)); |
| 181 | const group_raw_data = self.shdrContents(shndx); | 189 | const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 190 | defer allocator.free(group_raw_data); | ||
| 182 | const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32)); | 191 | const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32)); |
| 183 | const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; | 192 | const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; |
| 184 | 193 | ||
| ... | @@ -188,14 +197,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { | ... | @@ -188,14 +197,20 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 188 | continue; | 197 | continue; |
| 189 | } | 198 | } |
| 190 | 199 | ||
| 200 | const group_start = @as(u32, @intCast(self.comdat_group_data.items.len)); | ||
| 201 | try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]); | ||
| 202 | |||
| 191 | const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature); | 203 | const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature); |
| 192 | const comdat_group_index = try elf_file.addComdatGroup(); | 204 | const comdat_group_index = try elf_file.addComdatGroup(); |
| 193 | const comdat_group = elf_file.comdatGroup(comdat_group_index); | 205 | const comdat_group = elf_file.comdatGroup(comdat_group_index); |
| 194 | comdat_group.* = .{ | 206 | comdat_group.* = .{ |
| 195 | .owner = gop.index, | 207 | .owner = gop.index, |
| 208 | .file = self.index, | ||
| 196 | .shndx = shndx, | 209 | .shndx = shndx, |
| 210 | .members_start = group_start, | ||
| 211 | .members_len = @intCast(group_nmembers - 1), | ||
| 197 | }; | 212 | }; |
| 198 | try self.comdat_groups.append(gpa, comdat_group_index); | 213 | try self.comdat_groups.append(allocator, comdat_group_index); |
| 199 | }, | 214 | }, |
| 200 | 215 | ||
| 201 | elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), | 216 | elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), |
| ... | @@ -210,7 +225,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { | ... | @@ -210,7 +225,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 210 | else => { | 225 | else => { |
| 211 | const shndx = @as(u16, @intCast(i)); | 226 | const shndx = @as(u16, @intCast(i)); |
| 212 | if (self.skipShdr(shndx, elf_file)) continue; | 227 | if (self.skipShdr(shndx, elf_file)) continue; |
| 213 | try self.addAtom(shdr, shndx, elf_file); | 228 | try self.addAtom(allocator, handle, shdr, shndx, elf_file); |
| 214 | }, | 229 | }, |
| 215 | } | 230 | } |
| 216 | } | 231 | } |
| ... | @@ -220,14 +235,19 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { | ... | @@ -220,14 +235,19 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { |
| 220 | elf.SHT_REL, elf.SHT_RELA => { | 235 | elf.SHT_REL, elf.SHT_RELA => { |
| 221 | const atom_index = self.atoms.items[shdr.sh_info]; | 236 | const atom_index = self.atoms.items[shdr.sh_info]; |
| 222 | if (elf_file.atom(atom_index)) |atom| { | 237 | if (elf_file.atom(atom_index)) |atom| { |
| 223 | atom.relocs_section_index = @as(u16, @intCast(i)); | 238 | const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i)); |
| 239 | defer allocator.free(relocs); | ||
| 240 | atom.relocs_section_index = @intCast(i); | ||
| 241 | atom.rel_index = @intCast(self.relocs.items.len); | ||
| 242 | atom.rel_num = @intCast(relocs.len); | ||
| 243 | try self.relocs.appendUnalignedSlice(allocator, relocs); | ||
| 224 | } | 244 | } |
| 225 | }, | 245 | }, |
| 226 | else => {}, | 246 | else => {}, |
| 227 | }; | 247 | }; |
| 228 | } | 248 | } |
| 229 | 249 | ||
| 230 | fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOfMemory}!void { | 250 | fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void { |
| 231 | const atom_index = try elf_file.addAtom(); | 251 | const atom_index = try elf_file.addAtom(); |
| 232 | const atom = elf_file.atom(atom_index).?; | 252 | const atom = elf_file.atom(atom_index).?; |
| 233 | atom.atom_index = atom_index; | 253 | atom.atom_index = atom_index; |
| ... | @@ -237,7 +257,8 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf | ... | @@ -237,7 +257,8 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf |
| 237 | self.atoms.items[shndx] = atom_index; | 257 | self.atoms.items[shndx] = atom_index; |
| 238 | 258 | ||
| 239 | if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { | 259 | if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { |
| 240 | const data = self.shdrContents(shndx); | 260 | const data = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 261 | defer allocator.free(data); | ||
| 241 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; | 262 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 242 | atom.size = chdr.ch_size; | 263 | atom.size = chdr.ch_size; |
| 243 | atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign); | 264 | atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign); |
| ... | @@ -247,7 +268,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf | ... | @@ -247,7 +268,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf |
| 247 | } | 268 | } |
| 248 | } | 269 | } |
| 249 | 270 | ||
| 250 | fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 { | 271 | fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 { |
| 251 | const name = blk: { | 272 | const name = blk: { |
| 252 | const name = self.getString(shdr.sh_name); | 273 | const name = self.getString(shdr.sh_name); |
| 253 | if (elf_file.base.isRelocatable()) break :blk name; | 274 | if (elf_file.base.isRelocatable()) break :blk name; |
| ... | @@ -310,12 +331,10 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { | ... | @@ -310,12 +331,10 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { |
| 310 | return ignore; | 331 | return ignore; |
| 311 | } | 332 | } |
| 312 | 333 | ||
| 313 | fn initSymtab(self: *Object, elf_file: *Elf) !void { | 334 | fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void { |
| 314 | const comp = elf_file.base.comp; | ||
| 315 | const gpa = comp.gpa; | ||
| 316 | const first_global = self.first_global orelse self.symtab.items.len; | 335 | const first_global = self.first_global orelse self.symtab.items.len; |
| 317 | 336 | ||
| 318 | try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len); | 337 | try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len); |
| 319 | 338 | ||
| 320 | for (self.symtab.items[0..first_global], 0..) |sym, i| { | 339 | for (self.symtab.items[0..first_global], 0..) |sym, i| { |
| 321 | const index = try elf_file.addSymbol(); | 340 | const index = try elf_file.addSymbol(); |
| ... | @@ -335,19 +354,24 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { | ... | @@ -335,19 +354,24 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { |
| 335 | } | 354 | } |
| 336 | } | 355 | } |
| 337 | 356 | ||
| 338 | fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { | 357 | fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void { |
| 339 | const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { | 358 | const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { |
| 340 | elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u16, @intCast(i)), | 359 | elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)), |
| 341 | else => {}, | 360 | else => {}, |
| 342 | } else { | 361 | } else { |
| 362 | // TODO: convert into an error | ||
| 343 | log.debug("{s}: missing reloc section for unwind info section", .{self.fmtPath()}); | 363 | log.debug("{s}: missing reloc section for unwind info section", .{self.fmtPath()}); |
| 344 | return; | 364 | return; |
| 345 | }; | 365 | }; |
| 346 | 366 | ||
| 347 | const comp = elf_file.base.comp; | 367 | const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 348 | const gpa = comp.gpa; | 368 | defer allocator.free(raw); |
| 349 | const raw = self.shdrContents(shndx); | 369 | const data_start = @as(u32, @intCast(self.eh_frame_data.items.len)); |
| 350 | const relocs = self.getRelocs(relocs_shndx); | 370 | try self.eh_frame_data.appendSlice(allocator, raw); |
| 371 | const relocs = try self.preadRelocsAlloc(allocator, handle, relocs_shndx); | ||
| 372 | defer allocator.free(relocs); | ||
| 373 | const rel_start = @as(u32, @intCast(self.relocs.items.len)); | ||
| 374 | try self.relocs.appendUnalignedSlice(allocator, relocs); | ||
| 351 | const fdes_start = self.fdes.items.len; | 375 | const fdes_start = self.fdes.items.len; |
| 352 | const cies_start = self.cies.items.len; | 376 | const cies_start = self.cies.items.len; |
| 353 | 377 | ||
| ... | @@ -355,22 +379,20 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { | ... | @@ -355,22 +379,20 @@ fn parseEhFrame(self: *Object, shndx: u16, elf_file: *Elf) !void { |
| 355 | while (try it.next()) |rec| { | 379 | while (try it.next()) |rec| { |
| 356 | const rel_range = filterRelocs(relocs, rec.offset, rec.size + 4); | 380 | const rel_range = filterRelocs(relocs, rec.offset, rec.size + 4); |
| 357 | switch (rec.tag) { | 381 | switch (rec.tag) { |
| 358 | .cie => try self.cies.append(gpa, .{ | 382 | .cie => try self.cies.append(allocator, .{ |
| 359 | .offset = rec.offset, | 383 | .offset = data_start + rec.offset, |
| 360 | .size = rec.size, | 384 | .size = rec.size, |
| 361 | .rel_index = @as(u32, @intCast(rel_range.start)), | 385 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), |
| 362 | .rel_num = @as(u32, @intCast(rel_range.len)), | 386 | .rel_num = @as(u32, @intCast(rel_range.len)), |
| 363 | .rel_section_index = relocs_shndx, | ||
| 364 | .input_section_index = shndx, | 387 | .input_section_index = shndx, |
| 365 | .file_index = self.index, | 388 | .file_index = self.index, |
| 366 | }), | 389 | }), |
| 367 | .fde => try self.fdes.append(gpa, .{ | 390 | .fde => try self.fdes.append(allocator, .{ |
| 368 | .offset = rec.offset, | 391 | .offset = data_start + rec.offset, |
| 369 | .size = rec.size, | 392 | .size = rec.size, |
| 370 | .cie_index = undefined, | 393 | .cie_index = undefined, |
| 371 | .rel_index = @as(u32, @intCast(rel_range.start)), | 394 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), |
| 372 | .rel_num = @as(u32, @intCast(rel_range.len)), | 395 | .rel_num = @as(u32, @intCast(rel_range.len)), |
| 373 | .rel_section_index = relocs_shndx, | ||
| 374 | .input_section_index = shndx, | 396 | .input_section_index = shndx, |
| 375 | .file_index = self.index, | 397 | .file_index = self.index, |
| 376 | }), | 398 | }), |
| ... | @@ -759,6 +781,12 @@ pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void { | ... | @@ -759,6 +781,12 @@ pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void { |
| 759 | } | 781 | } |
| 760 | } | 782 | } |
| 761 | 783 | ||
| 784 | pub fn parseAr(self: *Object, elf_file: *Elf) !void { | ||
| 785 | const gpa = elf_file.base.comp.gpa; | ||
| 786 | const handle = elf_file.fileHandle(self.file_handle); | ||
| 787 | try self.parseCommon(gpa, handle, elf_file); | ||
| 788 | } | ||
| 789 | |||
| 762 | pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { | 790 | pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void { |
| 763 | const comp = elf_file.base.comp; | 791 | const comp = elf_file.base.comp; |
| 764 | const gpa = comp.gpa; | 792 | const gpa = comp.gpa; |
| ... | @@ -773,21 +801,30 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf | ... | @@ -773,21 +801,30 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf |
| 773 | } | 801 | } |
| 774 | } | 802 | } |
| 775 | 803 | ||
| 776 | pub fn updateArSize(self: *Object) void { | 804 | pub fn updateArSize(self: *Object, elf_file: *Elf) !void { |
| 777 | self.output_ar_state.size = self.data.len; | 805 | const handle = elf_file.fileHandle(self.file_handle); |
| 806 | const size = (try handle.stat()).size; | ||
| 807 | self.output_ar_state.size = size; | ||
| 778 | } | 808 | } |
| 779 | 809 | ||
| 780 | pub fn writeAr(self: Object, writer: anytype) !void { | 810 | pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { |
| 811 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; | ||
| 781 | const name = self.path; | 812 | const name = self.path; |
| 782 | const hdr = Archive.setArHdr(.{ | 813 | const hdr = Archive.setArHdr(.{ |
| 783 | .name = if (name.len <= Archive.max_member_name_len) | 814 | .name = if (name.len <= Archive.max_member_name_len) |
| 784 | .{ .name = name } | 815 | .{ .name = name } |
| 785 | else | 816 | else |
| 786 | .{ .name_off = self.output_ar_state.name_off }, | 817 | .{ .name_off = self.output_ar_state.name_off }, |
| 787 | .size = @intCast(self.data.len), | 818 | .size = size, |
| 788 | }); | 819 | }); |
| 789 | try writer.writeAll(mem.asBytes(&hdr)); | 820 | try writer.writeAll(mem.asBytes(&hdr)); |
| 790 | try writer.writeAll(self.data); | 821 | const handle = elf_file.fileHandle(self.file_handle); |
| 822 | const gpa = elf_file.base.comp.gpa; | ||
| 823 | const data = try gpa.alloc(u8, size); | ||
| 824 | defer gpa.free(data); | ||
| 825 | const amt = try handle.preadAll(data, 0); | ||
| 826 | if (amt != size) return error.InputOutput; | ||
| 827 | try writer.writeAll(data); | ||
| 791 | } | 828 | } |
| 792 | 829 | ||
| 793 | pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { | 830 | pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void { |
| ... | @@ -859,12 +896,6 @@ pub fn globals(self: Object) []const Symbol.Index { | ... | @@ -859,12 +896,6 @@ pub fn globals(self: Object) []const Symbol.Index { |
| 859 | return self.symbols.items[start..]; | 896 | return self.symbols.items[start..]; |
| 860 | } | 897 | } |
| 861 | 898 | ||
| 862 | pub fn shdrContents(self: Object, index: u32) []const u8 { | ||
| 863 | assert(index < self.shdrs.items.len); | ||
| 864 | const shdr = self.shdrs.items[index]; | ||
| 865 | return self.data[shdr.sh_offset..][0..shdr.sh_size]; | ||
| 866 | } | ||
| 867 | |||
| 868 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). | 899 | /// Returns atom's code and optionally uncompresses data if required (for compressed sections). |
| 869 | /// Caller owns the memory. | 900 | /// Caller owns the memory. |
| 870 | pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { | 901 | pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { |
| ... | @@ -872,8 +903,11 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) | ... | @@ -872,8 +903,11 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) |
| 872 | const gpa = comp.gpa; | 903 | const gpa = comp.gpa; |
| 873 | const atom_ptr = elf_file.atom(atom_index).?; | 904 | const atom_ptr = elf_file.atom(atom_index).?; |
| 874 | assert(atom_ptr.file_index == self.index); | 905 | assert(atom_ptr.file_index == self.index); |
| 875 | const data = self.shdrContents(atom_ptr.input_section_index); | ||
| 876 | const shdr = atom_ptr.inputShdr(elf_file); | 906 | const shdr = atom_ptr.inputShdr(elf_file); |
| 907 | const handle = elf_file.fileHandle(self.file_handle); | ||
| 908 | const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index); | ||
| 909 | defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data); | ||
| 910 | |||
| 877 | if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { | 911 | if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { |
| 878 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; | 912 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 879 | switch (chdr.ch_type) { | 913 | switch (chdr.ch_type) { |
| ... | @@ -892,31 +926,37 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) | ... | @@ -892,31 +926,37 @@ pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) |
| 892 | }, | 926 | }, |
| 893 | else => @panic("TODO unhandled compression scheme"), | 927 | else => @panic("TODO unhandled compression scheme"), |
| 894 | } | 928 | } |
| 895 | } else return gpa.dupe(u8, data); | 929 | } |
| 896 | } | ||
| 897 | 930 | ||
| 898 | pub fn comdatGroupMembers(self: *Object, index: u16) []align(1) const u32 { | 931 | return data; |
| 899 | const raw = self.shdrContents(index); | ||
| 900 | const nmembers = @divExact(raw.len, @sizeOf(u32)); | ||
| 901 | const members = @as([*]align(1) const u32, @ptrCast(raw.ptr))[1..nmembers]; | ||
| 902 | return members; | ||
| 903 | } | 932 | } |
| 904 | 933 | ||
| 905 | pub fn asFile(self: *Object) File { | 934 | pub fn asFile(self: *Object) File { |
| 906 | return .{ .object = self }; | 935 | return .{ .object = self }; |
| 907 | } | 936 | } |
| 908 | 937 | ||
| 909 | pub fn getRelocs(self: *Object, shndx: u32) []align(1) const elf.Elf64_Rela { | ||
| 910 | const raw = self.shdrContents(shndx); | ||
| 911 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); | ||
| 912 | return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; | ||
| 913 | } | ||
| 914 | |||
| 915 | pub fn getString(self: Object, off: u32) [:0]const u8 { | 938 | pub fn getString(self: Object, off: u32) [:0]const u8 { |
| 916 | assert(off < self.strtab.items.len); | 939 | assert(off < self.strtab.items.len); |
| 917 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | 940 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 918 | } | 941 | } |
| 919 | 942 | ||
| 943 | /// Caller owns the memory. | ||
| 944 | fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 { | ||
| 945 | assert(index < self.shdrs.items.len); | ||
| 946 | const offset = if (self.archive) |ar| ar.offset else 0; | ||
| 947 | const shdr = self.shdrs.items[index]; | ||
| 948 | const sh_offset = math.cast(u64, shdr.sh_offset) orelse return error.Overflow; | ||
| 949 | const sh_size = math.cast(u64, shdr.sh_size) orelse return error.Overflow; | ||
| 950 | return Elf.preadAllAlloc(allocator, handle, offset + sh_offset, sh_size); | ||
| 951 | } | ||
| 952 | |||
| 953 | /// Caller owns the memory. | ||
| 954 | fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { | ||
| 955 | const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); | ||
| 956 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); | ||
| 957 | return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; | ||
| 958 | } | ||
| 959 | |||
| 920 | pub fn format( | 960 | pub fn format( |
| 921 | self: *Object, | 961 | self: *Object, |
| 922 | comptime unused_fmt_string: []const u8, | 962 | comptime unused_fmt_string: []const u8, |
| ... | @@ -1053,7 +1093,7 @@ fn formatComdatGroups( | ... | @@ -1053,7 +1093,7 @@ fn formatComdatGroups( |
| 1053 | const cg_owner = elf_file.comdatGroupOwner(cg.owner); | 1093 | const cg_owner = elf_file.comdatGroupOwner(cg.owner); |
| 1054 | if (cg_owner.file != object.index) continue; | 1094 | if (cg_owner.file != object.index) continue; |
| 1055 | try writer.print(" COMDAT({d})\n", .{cg_index}); | 1095 | try writer.print(" COMDAT({d})\n", .{cg_index}); |
| 1056 | const cg_members = object.comdatGroupMembers(cg.shndx); | 1096 | const cg_members = cg.comdatGroupMembers(elf_file); |
| 1057 | for (cg_members) |shndx| { | 1097 | for (cg_members) |shndx| { |
| 1058 | const atom_index = object.atoms.items[shndx]; | 1098 | const atom_index = object.atoms.items[shndx]; |
| 1059 | const atom = elf_file.atom(atom_index) orelse continue; | 1099 | const atom = elf_file.atom(atom_index) orelse continue; |
| ... | @@ -1074,40 +1114,17 @@ fn formatPath( | ... | @@ -1074,40 +1114,17 @@ fn formatPath( |
| 1074 | ) !void { | 1114 | ) !void { |
| 1075 | _ = unused_fmt_string; | 1115 | _ = unused_fmt_string; |
| 1076 | _ = options; | 1116 | _ = options; |
| 1077 | if (object.archive) |path| { | 1117 | if (object.archive) |ar| { |
| 1078 | try writer.writeAll(path); | 1118 | try writer.writeAll(ar.path); |
| 1079 | try writer.writeByte('('); | 1119 | try writer.writeByte('('); |
| 1080 | try writer.writeAll(object.path); | 1120 | try writer.writeAll(object.path); |
| 1081 | try writer.writeByte(')'); | 1121 | try writer.writeByte(')'); |
| 1082 | } else try writer.writeAll(object.path); | 1122 | } else try writer.writeAll(object.path); |
| 1083 | } | 1123 | } |
| 1084 | 1124 | ||
| 1085 | pub const ElfShdr = struct { | 1125 | const InArchive = struct { |
| 1086 | sh_name: u32, | 1126 | path: []const u8, |
| 1087 | sh_type: u32, | 1127 | offset: u64, |
| 1088 | sh_flags: u64, | ||
| 1089 | sh_addr: u64, | ||
| 1090 | sh_offset: usize, | ||
| 1091 | sh_size: usize, | ||
| 1092 | sh_link: u32, | ||
| 1093 | sh_info: u32, | ||
| 1094 | sh_addralign: u64, | ||
| 1095 | sh_entsize: u64, | ||
| 1096 | |||
| 1097 | pub fn fromElf64Shdr(shdr: elf.Elf64_Shdr) error{Overflow}!ElfShdr { | ||
| 1098 | return .{ | ||
| 1099 | .sh_name = shdr.sh_name, | ||
| 1100 | .sh_type = shdr.sh_type, | ||
| 1101 | .sh_flags = shdr.sh_flags, | ||
| 1102 | .sh_addr = shdr.sh_addr, | ||
| 1103 | .sh_offset = math.cast(usize, shdr.sh_offset) orelse return error.Overflow, | ||
| 1104 | .sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow, | ||
| 1105 | .sh_link = shdr.sh_link, | ||
| 1106 | .sh_info = shdr.sh_info, | ||
| 1107 | .sh_addralign = shdr.sh_addralign, | ||
| 1108 | .sh_entsize = shdr.sh_entsize, | ||
| 1109 | }; | ||
| 1110 | } | ||
| 1111 | }; | 1128 | }; |
| 1112 | 1129 | ||
| 1113 | const Object = @This(); | 1130 | const Object = @This(); |
src/link/Elf/SharedObject.zig+88-77| ... | @@ -1,22 +1,18 @@ | ... | @@ -1,22 +1,18 @@ |
| 1 | path: []const u8, | 1 | path: []const u8, |
| 2 | data: []const u8, | ||
| 3 | index: File.Index, | 2 | index: File.Index, |
| 4 | 3 | ||
| 5 | header: ?elf.Elf64_Ehdr = null, | 4 | header: ?elf.Elf64_Ehdr = null, |
| 6 | shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, | 5 | shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, |
| 7 | 6 | ||
| 8 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, | 7 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{}, |
| 9 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 8 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 10 | /// Version symtab contains version strings of the symbols if present. | 9 | /// Version symtab contains version strings of the symbols if present. |
| 11 | versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, | 10 | versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, |
| 12 | verstrings: std.ArrayListUnmanaged(u32) = .{}, | 11 | verstrings: std.ArrayListUnmanaged(u32) = .{}, |
| 12 | |||
| 13 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 13 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 14 | aliases: ?std.ArrayListUnmanaged(u32) = null, | 14 | aliases: ?std.ArrayListUnmanaged(u32) = null, |
| 15 | 15 | dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{}, | |
| 16 | dynsym_sect_index: ?u16 = null, | ||
| 17 | dynamic_sect_index: ?u16 = null, | ||
| 18 | versym_sect_index: ?u16 = null, | ||
| 19 | verdef_sect_index: ?u16 = null, | ||
| 20 | 16 | ||
| 21 | needed: bool, | 17 | needed: bool, |
| 22 | alive: bool, | 18 | alive: bool, |
| ... | @@ -36,23 +32,24 @@ pub fn isSharedObject(path: []const u8) !bool { | ... | @@ -36,23 +32,24 @@ pub fn isSharedObject(path: []const u8) !bool { |
| 36 | 32 | ||
| 37 | pub fn deinit(self: *SharedObject, allocator: Allocator) void { | 33 | pub fn deinit(self: *SharedObject, allocator: Allocator) void { |
| 38 | allocator.free(self.path); | 34 | allocator.free(self.path); |
| 39 | allocator.free(self.data); | 35 | self.shdrs.deinit(allocator); |
| 40 | self.symtab.deinit(allocator); | 36 | self.symtab.deinit(allocator); |
| 41 | self.strtab.deinit(allocator); | 37 | self.strtab.deinit(allocator); |
| 42 | self.versyms.deinit(allocator); | 38 | self.versyms.deinit(allocator); |
| 43 | self.verstrings.deinit(allocator); | 39 | self.verstrings.deinit(allocator); |
| 44 | self.symbols.deinit(allocator); | 40 | self.symbols.deinit(allocator); |
| 45 | if (self.aliases) |*aliases| aliases.deinit(allocator); | 41 | if (self.aliases) |*aliases| aliases.deinit(allocator); |
| 46 | self.shdrs.deinit(allocator); | 42 | self.dynamic_table.deinit(allocator); |
| 47 | } | 43 | } |
| 48 | 44 | ||
| 49 | pub fn parse(self: *SharedObject, elf_file: *Elf) !void { | 45 | pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { |
| 50 | const comp = elf_file.base.comp; | 46 | const comp = elf_file.base.comp; |
| 51 | const gpa = comp.gpa; | 47 | const gpa = comp.gpa; |
| 52 | var stream = std.io.fixedBufferStream(self.data); | 48 | const file_size = (try handle.stat()).size; |
| 53 | const reader = stream.reader(); | ||
| 54 | 49 | ||
| 55 | self.header = try reader.readStruct(elf.Elf64_Ehdr); | 50 | const header_buffer = try Elf.preadAllAlloc(gpa, handle, 0, @sizeOf(elf.Elf64_Ehdr)); |
| 51 | defer gpa.free(header_buffer); | ||
| 52 | self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; | ||
| 56 | 53 | ||
| 57 | const target = elf_file.base.comp.root_mod.resolved_target.result; | 54 | const target = elf_file.base.comp.root_mod.resolved_target.result; |
| 58 | if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { | 55 | if (target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) { |
| ... | @@ -64,9 +61,10 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { | ... | @@ -64,9 +61,10 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { |
| 64 | return error.InvalidCpuArch; | 61 | return error.InvalidCpuArch; |
| 65 | } | 62 | } |
| 66 | 63 | ||
| 67 | if (self.data.len < self.header.?.e_shoff or | 64 | const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; |
| 68 | self.data.len < self.header.?.e_shoff + @as(u64, @intCast(self.header.?.e_shnum)) * @sizeOf(elf.Elf64_Shdr)) | 65 | const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; |
| 69 | { | 66 | const shsize = shnum * @sizeOf(elf.Elf64_Shdr); |
| 67 | if (file_size < shoff or file_size < shoff + shsize) { | ||
| 70 | try elf_file.reportParseError2( | 68 | try elf_file.reportParseError2( |
| 71 | self.index, | 69 | self.index, |
| 72 | "corrupted header: section header table extends past the end of file", | 70 | "corrupted header: section header table extends past the end of file", |
| ... | @@ -75,45 +73,84 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { | ... | @@ -75,45 +73,84 @@ pub fn parse(self: *SharedObject, elf_file: *Elf) !void { |
| 75 | return error.MalformedObject; | 73 | return error.MalformedObject; |
| 76 | } | 74 | } |
| 77 | 75 | ||
| 78 | const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; | 76 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize); |
| 79 | 77 | defer gpa.free(shdrs_buffer); | |
| 80 | const shdrs = @as( | 78 | const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; |
| 81 | [*]align(1) const elf.Elf64_Shdr, | 79 | try self.shdrs.appendUnalignedSlice(gpa, shdrs); |
| 82 | @ptrCast(self.data.ptr + shoff), | ||
| 83 | )[0..self.header.?.e_shnum]; | ||
| 84 | try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len); | ||
| 85 | 80 | ||
| 86 | for (shdrs, 0..) |shdr, i| { | 81 | var dynsym_sect_index: ?u32 = null; |
| 82 | var dynamic_sect_index: ?u32 = null; | ||
| 83 | var versym_sect_index: ?u32 = null; | ||
| 84 | var verdef_sect_index: ?u32 = null; | ||
| 85 | for (self.shdrs.items, 0..) |shdr, i| { | ||
| 87 | if (shdr.sh_type != elf.SHT_NOBITS) { | 86 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 88 | if (self.data.len < shdr.sh_offset or self.data.len < shdr.sh_offset + shdr.sh_size) { | 87 | if (file_size < shdr.sh_offset or file_size < shdr.sh_offset + shdr.sh_size) { |
| 89 | try elf_file.reportParseError2(self.index, "corrupted section header", .{}); | 88 | try elf_file.reportParseError2(self.index, "corrupted section header", .{}); |
| 90 | return error.MalformedObject; | 89 | return error.MalformedObject; |
| 91 | } | 90 | } |
| 92 | } | 91 | } |
| 93 | self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); | ||
| 94 | switch (shdr.sh_type) { | 92 | switch (shdr.sh_type) { |
| 95 | elf.SHT_DYNSYM => self.dynsym_sect_index = @as(u16, @intCast(i)), | 93 | elf.SHT_DYNSYM => dynsym_sect_index = @intCast(i), |
| 96 | elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)), | 94 | elf.SHT_DYNAMIC => dynamic_sect_index = @intCast(i), |
| 97 | elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)), | 95 | elf.SHT_GNU_VERSYM => versym_sect_index = @intCast(i), |
| 98 | elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)), | 96 | elf.SHT_GNU_VERDEF => verdef_sect_index = @intCast(i), |
| 99 | else => {}, | 97 | else => {}, |
| 100 | } | 98 | } |
| 101 | } | 99 | } |
| 102 | 100 | ||
| 103 | try self.parseVersions(elf_file); | 101 | if (dynamic_sect_index) |index| { |
| 102 | const shdr = self.shdrs.items[index]; | ||
| 103 | const raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); | ||
| 104 | defer gpa.free(raw); | ||
| 105 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn)); | ||
| 106 | const dyntab = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num]; | ||
| 107 | try self.dynamic_table.appendUnalignedSlice(gpa, dyntab); | ||
| 108 | } | ||
| 109 | |||
| 110 | const symtab = if (dynsym_sect_index) |index| blk: { | ||
| 111 | const shdr = self.shdrs.items[index]; | ||
| 112 | const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); | ||
| 113 | const nsyms = @divExact(buffer.len, @sizeOf(elf.Elf64_Sym)); | ||
| 114 | break :blk @as([*]align(1) const elf.Elf64_Sym, @ptrCast(buffer.ptr))[0..nsyms]; | ||
| 115 | } else &[0]elf.Elf64_Sym{}; | ||
| 116 | defer gpa.free(symtab); | ||
| 117 | |||
| 118 | const strtab = if (dynsym_sect_index) |index| blk: { | ||
| 119 | const symtab_shdr = self.shdrs.items[index]; | ||
| 120 | const shdr = self.shdrs.items[symtab_shdr.sh_link]; | ||
| 121 | const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); | ||
| 122 | break :blk buffer; | ||
| 123 | } else &[0]u8{}; | ||
| 124 | defer gpa.free(strtab); | ||
| 125 | |||
| 126 | try self.parseVersions(elf_file, handle, .{ | ||
| 127 | .symtab = symtab, | ||
| 128 | .verdef_sect_index = verdef_sect_index, | ||
| 129 | .versym_sect_index = versym_sect_index, | ||
| 130 | }); | ||
| 131 | |||
| 132 | try self.initSymtab(elf_file, .{ | ||
| 133 | .symtab = symtab, | ||
| 134 | .strtab = strtab, | ||
| 135 | }); | ||
| 104 | } | 136 | } |
| 105 | 137 | ||
| 106 | fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { | 138 | fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: struct { |
| 139 | symtab: []align(1) const elf.Elf64_Sym, | ||
| 140 | verdef_sect_index: ?u32, | ||
| 141 | versym_sect_index: ?u32, | ||
| 142 | }) !void { | ||
| 107 | const comp = elf_file.base.comp; | 143 | const comp = elf_file.base.comp; |
| 108 | const gpa = comp.gpa; | 144 | const gpa = comp.gpa; |
| 109 | const symtab = self.getSymtabRaw(); | ||
| 110 | 145 | ||
| 111 | try self.verstrings.resize(gpa, 2); | 146 | try self.verstrings.resize(gpa, 2); |
| 112 | self.verstrings.items[elf.VER_NDX_LOCAL] = 0; | 147 | self.verstrings.items[elf.VER_NDX_LOCAL] = 0; |
| 113 | self.verstrings.items[elf.VER_NDX_GLOBAL] = 0; | 148 | self.verstrings.items[elf.VER_NDX_GLOBAL] = 0; |
| 114 | 149 | ||
| 115 | if (self.verdef_sect_index) |shndx| { | 150 | if (opts.verdef_sect_index) |shndx| { |
| 116 | const verdefs = self.shdrContents(shndx); | 151 | const shdr = self.shdrs.items[shndx]; |
| 152 | const verdefs = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); | ||
| 153 | defer gpa.free(verdefs); | ||
| 117 | const nverdefs = self.verdefNum(); | 154 | const nverdefs = self.verdefNum(); |
| 118 | try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs); | 155 | try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs); |
| 119 | 156 | ||
| ... | @@ -131,10 +168,12 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { | ... | @@ -131,10 +168,12 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { |
| 131 | } | 168 | } |
| 132 | } | 169 | } |
| 133 | 170 | ||
| 134 | try self.versyms.ensureTotalCapacityPrecise(gpa, symtab.len); | 171 | try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len); |
| 135 | 172 | ||
| 136 | if (self.versym_sect_index) |shndx| { | 173 | if (opts.versym_sect_index) |shndx| { |
| 137 | const versyms_raw = self.shdrContents(shndx); | 174 | const shdr = self.shdrs.items[shndx]; |
| 175 | const versyms_raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size); | ||
| 176 | defer gpa.free(versyms_raw); | ||
| 138 | const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym)); | 177 | const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym)); |
| 139 | const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms]; | 178 | const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms]; |
| 140 | for (versyms) |ver| { | 179 | for (versyms) |ver| { |
| ... | @@ -144,22 +183,23 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { | ... | @@ -144,22 +183,23 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { |
| 144 | ver; | 183 | ver; |
| 145 | self.versyms.appendAssumeCapacity(normalized_ver); | 184 | self.versyms.appendAssumeCapacity(normalized_ver); |
| 146 | } | 185 | } |
| 147 | } else for (0..symtab.len) |_| { | 186 | } else for (0..opts.symtab.len) |_| { |
| 148 | self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL); | 187 | self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL); |
| 149 | } | 188 | } |
| 150 | } | 189 | } |
| 151 | 190 | ||
| 152 | pub fn init(self: *SharedObject, elf_file: *Elf) !void { | 191 | fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct { |
| 192 | symtab: []align(1) const elf.Elf64_Sym, | ||
| 193 | strtab: []const u8, | ||
| 194 | }) !void { | ||
| 153 | const comp = elf_file.base.comp; | 195 | const comp = elf_file.base.comp; |
| 154 | const gpa = comp.gpa; | 196 | const gpa = comp.gpa; |
| 155 | const symtab = self.getSymtabRaw(); | ||
| 156 | const strtab = self.getStrtabRaw(); | ||
| 157 | 197 | ||
| 158 | try self.strtab.appendSlice(gpa, strtab); | 198 | try self.strtab.appendSlice(gpa, opts.strtab); |
| 159 | try self.symtab.ensureTotalCapacityPrecise(gpa, symtab.len); | 199 | try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len); |
| 160 | try self.symbols.ensureTotalCapacityPrecise(gpa, symtab.len); | 200 | try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len); |
| 161 | 201 | ||
| 162 | for (symtab, 0..) |sym, i| { | 202 | for (opts.symtab, 0..) |sym, i| { |
| 163 | const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0; | 203 | const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0; |
| 164 | const name = self.getString(sym.st_name); | 204 | const name = self.getString(sym.st_name); |
| 165 | // We need to garble up the name so that we don't pick this symbol | 205 | // We need to garble up the name so that we don't pick this symbol |
| ... | @@ -250,11 +290,6 @@ pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void { | ... | @@ -250,11 +290,6 @@ pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void { |
| 250 | } | 290 | } |
| 251 | } | 291 | } |
| 252 | 292 | ||
| 253 | pub fn shdrContents(self: SharedObject, index: u16) []const u8 { | ||
| 254 | const shdr = self.shdrs.items[index]; | ||
| 255 | return self.data[shdr.sh_offset..][0..shdr.sh_size]; | ||
| 256 | } | ||
| 257 | |||
| 258 | pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 { | 293 | pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 { |
| 259 | const off = self.verstrings.items[index & elf.VERSYM_VERSION]; | 294 | const off = self.verstrings.items[index & elf.VERSYM_VERSION]; |
| 260 | return self.getString(off); | 295 | return self.getString(off); |
| ... | @@ -264,16 +299,8 @@ pub fn asFile(self: *SharedObject) File { | ... | @@ -264,16 +299,8 @@ pub fn asFile(self: *SharedObject) File { |
| 264 | return .{ .shared_object = self }; | 299 | return .{ .shared_object = self }; |
| 265 | } | 300 | } |
| 266 | 301 | ||
| 267 | fn dynamicTable(self: *SharedObject) []align(1) const elf.Elf64_Dyn { | ||
| 268 | const shndx = self.dynamic_sect_index orelse return &[0]elf.Elf64_Dyn{}; | ||
| 269 | const raw = self.shdrContents(shndx); | ||
| 270 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn)); | ||
| 271 | return @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num]; | ||
| 272 | } | ||
| 273 | |||
| 274 | fn verdefNum(self: *SharedObject) u32 { | 302 | fn verdefNum(self: *SharedObject) u32 { |
| 275 | const entries = self.dynamicTable(); | 303 | for (self.dynamic_table.items) |entry| switch (entry.d_tag) { |
| 276 | for (entries) |entry| switch (entry.d_tag) { | ||
| 277 | elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)), | 304 | elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)), |
| 278 | else => {}, | 305 | else => {}, |
| 279 | }; | 306 | }; |
| ... | @@ -281,8 +308,7 @@ fn verdefNum(self: *SharedObject) u32 { | ... | @@ -281,8 +308,7 @@ fn verdefNum(self: *SharedObject) u32 { |
| 281 | } | 308 | } |
| 282 | 309 | ||
| 283 | pub fn soname(self: *SharedObject) []const u8 { | 310 | pub fn soname(self: *SharedObject) []const u8 { |
| 284 | const entries = self.dynamicTable(); | 311 | for (self.dynamic_table.items) |entry| switch (entry.d_tag) { |
| 285 | for (entries) |entry| switch (entry.d_tag) { | ||
| 286 | elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))), | 312 | elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))), |
| 287 | else => {}, | 313 | else => {}, |
| 288 | }; | 314 | }; |
| ... | @@ -342,20 +368,6 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 { | ... | @@ -342,20 +368,6 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 { |
| 342 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | 368 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); |
| 343 | } | 369 | } |
| 344 | 370 | ||
| 345 | pub fn getSymtabRaw(self: SharedObject) []align(1) const elf.Elf64_Sym { | ||
| 346 | const index = self.dynsym_sect_index orelse return &[0]elf.Elf64_Sym{}; | ||
| 347 | const raw_symtab = self.shdrContents(index); | ||
| 348 | const nsyms = @divExact(raw_symtab.len, @sizeOf(elf.Elf64_Sym)); | ||
| 349 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; | ||
| 350 | return symtab; | ||
| 351 | } | ||
| 352 | |||
| 353 | pub fn getStrtabRaw(self: SharedObject) []const u8 { | ||
| 354 | const index = self.dynsym_sect_index orelse return &[0]u8{}; | ||
| 355 | const shdr = self.shdrs.items[index]; | ||
| 356 | return self.shdrContents(@as(u16, @intCast(shdr.sh_link))); | ||
| 357 | } | ||
| 358 | |||
| 359 | pub fn format( | 371 | pub fn format( |
| 360 | self: SharedObject, | 372 | self: SharedObject, |
| 361 | comptime unused_fmt_string: []const u8, | 373 | comptime unused_fmt_string: []const u8, |
| ... | @@ -407,6 +419,5 @@ const mem = std.mem; | ... | @@ -407,6 +419,5 @@ const mem = std.mem; |
| 407 | 419 | ||
| 408 | const Allocator = mem.Allocator; | 420 | const Allocator = mem.Allocator; |
| 409 | const Elf = @import("../Elf.zig"); | 421 | const Elf = @import("../Elf.zig"); |
| 410 | const ElfShdr = @import("Object.zig").ElfShdr; | ||
| 411 | const File = @import("file.zig").File; | 422 | const File = @import("file.zig").File; |
| 412 | const Symbol = @import("Symbol.zig"); | 423 | const Symbol = @import("Symbol.zig"); |
src/link/Elf/ZigObject.zig+10-13| ... | @@ -305,19 +305,16 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { | ... | @@ -305,19 +305,16 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { |
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | /// TODO actually create fake input shdrs and return that instead. | 307 | /// TODO actually create fake input shdrs and return that instead. |
| 308 | pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr { | 308 | pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr { |
| 309 | _ = self; | 309 | _ = self; |
| 310 | const shdr = shdr: { | 310 | const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr; |
| 311 | const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr; | 311 | const shndx = atom.outputShndx() orelse return Elf.null_shdr; |
| 312 | const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr; | 312 | var shdr = elf_file.shdrs.items[shndx]; |
| 313 | var shdr = elf_file.shdrs.items[shndx]; | 313 | shdr.sh_addr = 0; |
| 314 | shdr.sh_addr = 0; | 314 | shdr.sh_offset = 0; |
| 315 | shdr.sh_offset = 0; | 315 | shdr.sh_size = atom.size; |
| 316 | shdr.sh_size = atom.size; | 316 | shdr.sh_addralign = atom.alignment.toByteUnits(1); |
| 317 | shdr.sh_addralign = atom.alignment.toByteUnits(1); | 317 | return shdr; |
| 318 | break :shdr shdr; | ||
| 319 | }; | ||
| 320 | return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable; | ||
| 321 | } | 318 | } |
| 322 | 319 | ||
| 323 | pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { | 320 | pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void { |
| ... | @@ -525,7 +522,7 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { | ... | @@ -525,7 +522,7 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { |
| 525 | .{ .name = name } | 522 | .{ .name = name } |
| 526 | else | 523 | else |
| 527 | .{ .name_off = self.output_ar_state.name_off }, | 524 | .{ .name_off = self.output_ar_state.name_off }, |
| 528 | .size = @intCast(self.data.items.len), | 525 | .size = self.data.items.len, |
| 529 | }); | 526 | }); |
| 530 | try writer.writeAll(mem.asBytes(&hdr)); | 527 | try writer.writeAll(mem.asBytes(&hdr)); |
| 531 | try writer.writeAll(self.data.items); | 528 | try writer.writeAll(self.data.items); |
src/link/Elf/eh_frame.zig+9-22| ... | @@ -5,7 +5,6 @@ pub const Fde = struct { | ... | @@ -5,7 +5,6 @@ pub const Fde = struct { |
| 5 | cie_index: u32, | 5 | cie_index: u32, |
| 6 | rel_index: u32 = 0, | 6 | rel_index: u32 = 0, |
| 7 | rel_num: u32 = 0, | 7 | rel_num: u32 = 0, |
| 8 | rel_section_index: u32 = 0, | ||
| 9 | input_section_index: u32 = 0, | 8 | input_section_index: u32 = 0, |
| 10 | file_index: u32 = 0, | 9 | file_index: u32 = 0, |
| 11 | alive: bool = true, | 10 | alive: bool = true, |
| ... | @@ -20,10 +19,9 @@ pub const Fde = struct { | ... | @@ -20,10 +19,9 @@ pub const Fde = struct { |
| 20 | return base + fde.out_offset; | 19 | return base + fde.out_offset; |
| 21 | } | 20 | } |
| 22 | 21 | ||
| 23 | pub fn data(fde: Fde, elf_file: *Elf) []const u8 { | 22 | pub fn data(fde: Fde, elf_file: *Elf) []u8 { |
| 24 | const object = elf_file.file(fde.file_index).?.object; | 23 | const object = elf_file.file(fde.file_index).?.object; |
| 25 | const contents = object.shdrContents(fde.input_section_index); | 24 | return object.eh_frame_data.items[fde.offset..][0..fde.calcSize()]; |
| 26 | return contents[fde.offset..][0..fde.calcSize()]; | ||
| 27 | } | 25 | } |
| 28 | 26 | ||
| 29 | pub fn cie(fde: Fde, elf_file: *Elf) Cie { | 27 | pub fn cie(fde: Fde, elf_file: *Elf) Cie { |
| ... | @@ -50,7 +48,7 @@ pub const Fde = struct { | ... | @@ -50,7 +48,7 @@ pub const Fde = struct { |
| 50 | 48 | ||
| 51 | pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela { | 49 | pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela { |
| 52 | const object = elf_file.file(fde.file_index).?.object; | 50 | const object = elf_file.file(fde.file_index).?.object; |
| 53 | return object.getRelocs(fde.rel_section_index)[fde.rel_index..][0..fde.rel_num]; | 51 | return object.relocs.items[fde.rel_index..][0..fde.rel_num]; |
| 54 | } | 52 | } |
| 55 | 53 | ||
| 56 | pub fn format( | 54 | pub fn format( |
| ... | @@ -106,7 +104,6 @@ pub const Cie = struct { | ... | @@ -106,7 +104,6 @@ pub const Cie = struct { |
| 106 | size: usize, | 104 | size: usize, |
| 107 | rel_index: u32 = 0, | 105 | rel_index: u32 = 0, |
| 108 | rel_num: u32 = 0, | 106 | rel_num: u32 = 0, |
| 109 | rel_section_index: u32 = 0, | ||
| 110 | input_section_index: u32 = 0, | 107 | input_section_index: u32 = 0, |
| 111 | file_index: u32 = 0, | 108 | file_index: u32 = 0, |
| 112 | /// Includes 4byte size cell. | 109 | /// Includes 4byte size cell. |
| ... | @@ -121,10 +118,9 @@ pub const Cie = struct { | ... | @@ -121,10 +118,9 @@ pub const Cie = struct { |
| 121 | return base + cie.out_offset; | 118 | return base + cie.out_offset; |
| 122 | } | 119 | } |
| 123 | 120 | ||
| 124 | pub fn data(cie: Cie, elf_file: *Elf) []const u8 { | 121 | pub fn data(cie: Cie, elf_file: *Elf) []u8 { |
| 125 | const object = elf_file.file(cie.file_index).?.object; | 122 | const object = elf_file.file(cie.file_index).?.object; |
| 126 | const contents = object.shdrContents(cie.input_section_index); | 123 | return object.eh_frame_data.items[cie.offset..][0..cie.calcSize()]; |
| 127 | return contents[cie.offset..][0..cie.calcSize()]; | ||
| 128 | } | 124 | } |
| 129 | 125 | ||
| 130 | pub fn calcSize(cie: Cie) usize { | 126 | pub fn calcSize(cie: Cie) usize { |
| ... | @@ -133,7 +129,7 @@ pub const Cie = struct { | ... | @@ -133,7 +129,7 @@ pub const Cie = struct { |
| 133 | 129 | ||
| 134 | pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela { | 130 | pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela { |
| 135 | const object = elf_file.file(cie.file_index).?.object; | 131 | const object = elf_file.file(cie.file_index).?.object; |
| 136 | return object.getRelocs(cie.rel_section_index)[cie.rel_index..][0..cie.rel_num]; | 132 | return object.relocs.items[cie.rel_index..][0..cie.rel_num]; |
| 137 | } | 133 | } |
| 138 | 134 | ||
| 139 | pub fn eql(cie: Cie, other: Cie, elf_file: *Elf) bool { | 135 | pub fn eql(cie: Cie, other: Cie, elf_file: *Elf) bool { |
| ... | @@ -330,9 +326,6 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: | ... | @@ -330,9 +326,6 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: |
| 330 | } | 326 | } |
| 331 | 327 | ||
| 332 | pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { | 328 | pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 333 | const comp = elf_file.base.comp; | ||
| 334 | const gpa = comp.gpa; | ||
| 335 | |||
| 336 | relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr}); | 329 | relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr}); |
| 337 | 330 | ||
| 338 | for (elf_file.objects.items) |index| { | 331 | for (elf_file.objects.items) |index| { |
| ... | @@ -341,8 +334,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { | ... | @@ -341,8 +334,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 341 | for (object.cies.items) |cie| { | 334 | for (object.cies.items) |cie| { |
| 342 | if (!cie.alive) continue; | 335 | if (!cie.alive) continue; |
| 343 | 336 | ||
| 344 | const contents = try gpa.dupe(u8, cie.data(elf_file)); | 337 | const contents = cie.data(elf_file); |
| 345 | defer gpa.free(contents); | ||
| 346 | 338 | ||
| 347 | for (cie.relocs(elf_file)) |rel| { | 339 | for (cie.relocs(elf_file)) |rel| { |
| 348 | const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); | 340 | const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); |
| ... | @@ -359,8 +351,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { | ... | @@ -359,8 +351,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 359 | for (object.fdes.items) |fde| { | 351 | for (object.fdes.items) |fde| { |
| 360 | if (!fde.alive) continue; | 352 | if (!fde.alive) continue; |
| 361 | 353 | ||
| 362 | const contents = try gpa.dupe(u8, fde.data(elf_file)); | 354 | const contents = fde.data(elf_file); |
| 363 | defer gpa.free(contents); | ||
| 364 | 355 | ||
| 365 | std.mem.writeInt( | 356 | std.mem.writeInt( |
| 366 | i32, | 357 | i32, |
| ... | @@ -382,9 +373,6 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { | ... | @@ -382,9 +373,6 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 382 | } | 373 | } |
| 383 | 374 | ||
| 384 | pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { | 375 | pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { |
| 385 | const comp = elf_file.base.comp; | ||
| 386 | const gpa = comp.gpa; | ||
| 387 | |||
| 388 | for (elf_file.objects.items) |index| { | 376 | for (elf_file.objects.items) |index| { |
| 389 | const object = elf_file.file(index).?.object; | 377 | const object = elf_file.file(index).?.object; |
| 390 | 378 | ||
| ... | @@ -400,8 +388,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { | ... | @@ -400,8 +388,7 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { |
| 400 | for (object.fdes.items) |fde| { | 388 | for (object.fdes.items) |fde| { |
| 401 | if (!fde.alive) continue; | 389 | if (!fde.alive) continue; |
| 402 | 390 | ||
| 403 | const contents = try gpa.dupe(u8, fde.data(elf_file)); | 391 | const contents = fde.data(elf_file); |
| 404 | defer gpa.free(contents); | ||
| 405 | 392 | ||
| 406 | std.mem.writeInt( | 393 | std.mem.writeInt( |
| 407 | i32, | 394 | i32, |
src/link/Elf/file.zig+7-4| ... | @@ -162,18 +162,18 @@ pub const File = union(enum) { | ... | @@ -162,18 +162,18 @@ pub const File = union(enum) { |
| 162 | state.name_off = try ar_strtab.insert(allocator, path); | 162 | state.name_off = try ar_strtab.insert(allocator, path); |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | pub fn updateArSize(file: File) void { | 165 | pub fn updateArSize(file: File, elf_file: *Elf) !void { |
| 166 | return switch (file) { | 166 | return switch (file) { |
| 167 | .zig_object => |x| x.updateArSize(), | 167 | .zig_object => |x| x.updateArSize(), |
| 168 | .object => |x| x.updateArSize(), | 168 | .object => |x| x.updateArSize(elf_file), |
| 169 | inline else => unreachable, | 169 | inline else => unreachable, |
| 170 | }; | 170 | }; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | pub fn writeAr(file: File, writer: anytype) !void { | 173 | pub fn writeAr(file: File, elf_file: *Elf, writer: anytype) !void { |
| 174 | return switch (file) { | 174 | return switch (file) { |
| 175 | .zig_object => |x| x.writeAr(writer), | 175 | .zig_object => |x| x.writeAr(writer), |
| 176 | .object => |x| x.writeAr(writer), | 176 | .object => |x| x.writeAr(elf_file, writer), |
| 177 | inline else => unreachable, | 177 | inline else => unreachable, |
| 178 | }; | 178 | }; |
| 179 | } | 179 | } |
| ... | @@ -187,6 +187,9 @@ pub const File = union(enum) { | ... | @@ -187,6 +187,9 @@ pub const File = union(enum) { |
| 187 | object: Object, | 187 | object: Object, |
| 188 | shared_object: SharedObject, | 188 | shared_object: SharedObject, |
| 189 | }; | 189 | }; |
| 190 | |||
| 191 | pub const Handle = std.fs.File; | ||
| 192 | pub const HandleIndex = Index; | ||
| 190 | }; | 193 | }; |
| 191 | 194 | ||
| 192 | const std = @import("std"); | 195 | const std = @import("std"); |
src/link/Elf/relocatable.zig created+565| ... | @@ -0,0 +1,565 @@ | ||
| 1 | pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { | ||
| 2 | const gpa = comp.gpa; | ||
| 3 | |||
| 4 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | ||
| 5 | defer positionals.deinit(); | ||
| 6 | |||
| 7 | try positionals.ensureUnusedCapacity(comp.objects.len); | ||
| 8 | positionals.appendSliceAssumeCapacity(comp.objects); | ||
| 9 | |||
| 10 | for (comp.c_object_table.keys()) |key| { | ||
| 11 | try positionals.append(.{ .path = key.status.success.object_path }); | ||
| 12 | } | ||
| 13 | |||
| 14 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | ||
| 15 | |||
| 16 | if (comp.include_compiler_rt) { | ||
| 17 | try positionals.append(.{ .path = comp.compiler_rt_obj.?.full_object_path }); | ||
| 18 | } | ||
| 19 | |||
| 20 | for (positionals.items) |obj| { | ||
| 21 | parsePositional(elf_file, obj.path) catch |err| switch (err) { | ||
| 22 | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported | ||
| 23 | error.UnknownFileType => try elf_file.reportParseError(obj.path, "unknown file type for an object file", .{}), | ||
| 24 | else => |e| try elf_file.reportParseError( | ||
| 25 | obj.path, | ||
| 26 | "unexpected error: parsing input file failed with error {s}", | ||
| 27 | .{@errorName(e)}, | ||
| 28 | ), | ||
| 29 | }; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 33 | |||
| 34 | // First, we flush relocatable object file generated with our backends. | ||
| 35 | if (elf_file.zigObjectPtr()) |zig_object| { | ||
| 36 | zig_object.resolveSymbols(elf_file); | ||
| 37 | zig_object.claimUnresolvedObject(elf_file); | ||
| 38 | |||
| 39 | try elf_file.initSymtab(); | ||
| 40 | try elf_file.initShStrtab(); | ||
| 41 | try elf_file.sortShdrs(); | ||
| 42 | try zig_object.addAtomsToRelaSections(elf_file); | ||
| 43 | try updateSectionSizes(elf_file); | ||
| 44 | |||
| 45 | try allocateAllocSections(elf_file); | ||
| 46 | try elf_file.allocateNonAllocSections(); | ||
| 47 | |||
| 48 | if (build_options.enable_logging) { | ||
| 49 | state_log.debug("{}", .{elf_file.dumpState()}); | ||
| 50 | } | ||
| 51 | |||
| 52 | try writeSyntheticSections(elf_file); | ||
| 53 | try elf_file.writeShdrTable(); | ||
| 54 | try elf_file.writeElfHeader(); | ||
| 55 | |||
| 56 | // TODO we can avoid reading in the file contents we just wrote if we give the linker | ||
| 57 | // ability to write directly to a buffer. | ||
| 58 | try zig_object.readFileContents(elf_file); | ||
| 59 | } | ||
| 60 | |||
| 61 | var files = std.ArrayList(File.Index).init(gpa); | ||
| 62 | defer files.deinit(); | ||
| 63 | try files.ensureTotalCapacityPrecise(elf_file.objects.items.len + 1); | ||
| 64 | if (elf_file.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index); | ||
| 65 | for (elf_file.objects.items) |index| files.appendAssumeCapacity(index); | ||
| 66 | |||
| 67 | // Update ar symtab from parsed objects | ||
| 68 | var ar_symtab: Archive.ArSymtab = .{}; | ||
| 69 | defer ar_symtab.deinit(gpa); | ||
| 70 | |||
| 71 | for (files.items) |index| { | ||
| 72 | try elf_file.file(index).?.updateArSymtab(&ar_symtab, elf_file); | ||
| 73 | } | ||
| 74 | |||
| 75 | ar_symtab.sort(); | ||
| 76 | |||
| 77 | // Save object paths in filenames strtab. | ||
| 78 | var ar_strtab: Archive.ArStrtab = .{}; | ||
| 79 | defer ar_strtab.deinit(gpa); | ||
| 80 | |||
| 81 | for (files.items) |index| { | ||
| 82 | const file_ptr = elf_file.file(index).?; | ||
| 83 | try file_ptr.updateArStrtab(gpa, &ar_strtab); | ||
| 84 | try file_ptr.updateArSize(elf_file); | ||
| 85 | } | ||
| 86 | |||
| 87 | // Update file offsets of contributing objects. | ||
| 88 | const total_size: usize = blk: { | ||
| 89 | var pos: usize = elf.ARMAG.len; | ||
| 90 | pos += @sizeOf(elf.ar_hdr) + ar_symtab.size(.p64); | ||
| 91 | |||
| 92 | if (ar_strtab.size() > 0) { | ||
| 93 | pos = mem.alignForward(usize, pos, 2); | ||
| 94 | pos += @sizeOf(elf.ar_hdr) + ar_strtab.size(); | ||
| 95 | } | ||
| 96 | |||
| 97 | for (files.items) |index| { | ||
| 98 | const file_ptr = elf_file.file(index).?; | ||
| 99 | const state = switch (file_ptr) { | ||
| 100 | .zig_object => |x| &x.output_ar_state, | ||
| 101 | .object => |x| &x.output_ar_state, | ||
| 102 | else => unreachable, | ||
| 103 | }; | ||
| 104 | pos = mem.alignForward(usize, pos, 2); | ||
| 105 | state.file_off = pos; | ||
| 106 | pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow); | ||
| 107 | } | ||
| 108 | |||
| 109 | break :blk pos; | ||
| 110 | }; | ||
| 111 | |||
| 112 | if (build_options.enable_logging) { | ||
| 113 | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(elf_file)}); | ||
| 114 | state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); | ||
| 115 | } | ||
| 116 | |||
| 117 | var buffer = std.ArrayList(u8).init(gpa); | ||
| 118 | defer buffer.deinit(); | ||
| 119 | try buffer.ensureTotalCapacityPrecise(total_size); | ||
| 120 | |||
| 121 | // Write magic | ||
| 122 | try buffer.writer().writeAll(elf.ARMAG); | ||
| 123 | |||
| 124 | // Write symtab | ||
| 125 | try ar_symtab.write(.p64, elf_file, buffer.writer()); | ||
| 126 | |||
| 127 | // Write strtab | ||
| 128 | if (ar_strtab.size() > 0) { | ||
| 129 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); | ||
| 130 | try ar_strtab.write(buffer.writer()); | ||
| 131 | } | ||
| 132 | |||
| 133 | // Write object files | ||
| 134 | for (files.items) |index| { | ||
| 135 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); | ||
| 136 | try elf_file.file(index).?.writeAr(elf_file, buffer.writer()); | ||
| 137 | } | ||
| 138 | |||
| 139 | assert(buffer.items.len == total_size); | ||
| 140 | |||
| 141 | try elf_file.base.file.?.setEndPos(total_size); | ||
| 142 | try elf_file.base.file.?.pwriteAll(buffer.items, 0); | ||
| 143 | |||
| 144 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { | ||
| 148 | const gpa = elf_file.base.comp.gpa; | ||
| 149 | |||
| 150 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | ||
| 151 | defer positionals.deinit(); | ||
| 152 | try positionals.ensureUnusedCapacity(comp.objects.len); | ||
| 153 | positionals.appendSliceAssumeCapacity(comp.objects); | ||
| 154 | |||
| 155 | // This is a set of object files emitted by clang in a single `build-exe` invocation. | ||
| 156 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up | ||
| 157 | // in this set. | ||
| 158 | for (comp.c_object_table.keys()) |key| { | ||
| 159 | try positionals.append(.{ .path = key.status.success.object_path }); | ||
| 160 | } | ||
| 161 | |||
| 162 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | ||
| 163 | |||
| 164 | for (positionals.items) |obj| { | ||
| 165 | elf_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | ||
| 166 | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported | ||
| 167 | else => |e| try elf_file.reportParseError( | ||
| 168 | obj.path, | ||
| 169 | "unexpected error: parsing input file failed with error {s}", | ||
| 170 | .{@errorName(e)}, | ||
| 171 | ), | ||
| 172 | }; | ||
| 173 | } | ||
| 174 | |||
| 175 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 176 | |||
| 177 | // Now, we are ready to resolve the symbols across all input files. | ||
| 178 | // We will first resolve the files in the ZigObject, next in the parsed | ||
| 179 | // input Object files. | ||
| 180 | elf_file.resolveSymbols(); | ||
| 181 | elf_file.markEhFrameAtomsDead(); | ||
| 182 | claimUnresolved(elf_file); | ||
| 183 | |||
| 184 | try initSections(elf_file); | ||
| 185 | try elf_file.sortShdrs(); | ||
| 186 | if (elf_file.zigObjectPtr()) |zig_object| { | ||
| 187 | try zig_object.addAtomsToRelaSections(elf_file); | ||
| 188 | } | ||
| 189 | for (elf_file.objects.items) |index| { | ||
| 190 | const object = elf_file.file(index).?.object; | ||
| 191 | try object.addAtomsToOutputSections(elf_file); | ||
| 192 | try object.addAtomsToRelaSections(elf_file); | ||
| 193 | } | ||
| 194 | try updateSectionSizes(elf_file); | ||
| 195 | |||
| 196 | try allocateAllocSections(elf_file); | ||
| 197 | try elf_file.allocateNonAllocSections(); | ||
| 198 | elf_file.allocateAtoms(); | ||
| 199 | |||
| 200 | if (build_options.enable_logging) { | ||
| 201 | state_log.debug("{}", .{elf_file.dumpState()}); | ||
| 202 | } | ||
| 203 | |||
| 204 | try writeAtoms(elf_file); | ||
| 205 | try writeSyntheticSections(elf_file); | ||
| 206 | try elf_file.writeShdrTable(); | ||
| 207 | try elf_file.writeElfHeader(); | ||
| 208 | |||
| 209 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 210 | } | ||
| 211 | |||
| 212 | fn parsePositional(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | ||
| 213 | if (try Object.isObject(path)) { | ||
| 214 | try parseObject(elf_file, path); | ||
| 215 | } else if (try Archive.isArchive(path)) { | ||
| 216 | try parseArchive(elf_file, path); | ||
| 217 | } else return error.UnknownFileType; | ||
| 218 | // TODO: should we check for LD script? | ||
| 219 | // Actually, should we even unpack an archive? | ||
| 220 | } | ||
| 221 | |||
| 222 | fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | ||
| 223 | const gpa = elf_file.base.comp.gpa; | ||
| 224 | const handle = try std.fs.cwd().openFile(path, .{}); | ||
| 225 | const fh = try elf_file.addFileHandle(handle); | ||
| 226 | |||
| 227 | const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa))); | ||
| 228 | elf_file.files.set(index, .{ .object = .{ | ||
| 229 | .path = try gpa.dupe(u8, path), | ||
| 230 | .file_handle = fh, | ||
| 231 | .index = index, | ||
| 232 | } }); | ||
| 233 | try elf_file.objects.append(gpa, index); | ||
| 234 | |||
| 235 | const object = elf_file.file(index).?.object; | ||
| 236 | try object.parseAr(elf_file); | ||
| 237 | } | ||
| 238 | |||
| 239 | fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | ||
| 240 | const gpa = elf_file.base.comp.gpa; | ||
| 241 | const handle = try std.fs.cwd().openFile(path, .{}); | ||
| 242 | const fh = try elf_file.addFileHandle(handle); | ||
| 243 | |||
| 244 | var archive = Archive{}; | ||
| 245 | defer archive.deinit(gpa); | ||
| 246 | try archive.parse(elf_file, path, fh); | ||
| 247 | |||
| 248 | const objects = try archive.objects.toOwnedSlice(gpa); | ||
| 249 | defer gpa.free(objects); | ||
| 250 | |||
| 251 | for (objects) |extracted| { | ||
| 252 | const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa))); | ||
| 253 | elf_file.files.set(index, .{ .object = extracted }); | ||
| 254 | const object = &elf_file.files.items(.data)[index].object; | ||
| 255 | object.index = index; | ||
| 256 | try object.parseAr(elf_file); | ||
| 257 | try elf_file.objects.append(gpa, index); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | fn claimUnresolved(elf_file: *Elf) void { | ||
| 262 | if (elf_file.zigObjectPtr()) |zig_object| { | ||
| 263 | zig_object.claimUnresolvedObject(elf_file); | ||
| 264 | } | ||
| 265 | for (elf_file.objects.items) |index| { | ||
| 266 | elf_file.file(index).?.object.claimUnresolvedObject(elf_file); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | fn initSections(elf_file: *Elf) !void { | ||
| 271 | const ptr_size = elf_file.ptrWidthBytes(); | ||
| 272 | |||
| 273 | for (elf_file.objects.items) |index| { | ||
| 274 | const object = elf_file.file(index).?.object; | ||
| 275 | try object.initOutputSections(elf_file); | ||
| 276 | try object.initRelaSections(elf_file); | ||
| 277 | } | ||
| 278 | |||
| 279 | const needs_eh_frame = for (elf_file.objects.items) |index| { | ||
| 280 | if (elf_file.file(index).?.object.cies.items.len > 0) break true; | ||
| 281 | } else false; | ||
| 282 | if (needs_eh_frame) { | ||
| 283 | elf_file.eh_frame_section_index = try elf_file.addSection(.{ | ||
| 284 | .name = ".eh_frame", | ||
| 285 | .type = elf.SHT_PROGBITS, | ||
| 286 | .flags = elf.SHF_ALLOC, | ||
| 287 | .addralign = ptr_size, | ||
| 288 | .offset = std.math.maxInt(u64), | ||
| 289 | }); | ||
| 290 | elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(".rela.eh_frame", elf_file.eh_frame_section_index.?); | ||
| 291 | } | ||
| 292 | |||
| 293 | try initComdatGroups(elf_file); | ||
| 294 | try elf_file.initSymtab(); | ||
| 295 | try elf_file.initShStrtab(); | ||
| 296 | } | ||
| 297 | |||
| 298 | fn initComdatGroups(elf_file: *Elf) !void { | ||
| 299 | const gpa = elf_file.base.comp.gpa; | ||
| 300 | |||
| 301 | for (elf_file.objects.items) |index| { | ||
| 302 | const object = elf_file.file(index).?.object; | ||
| 303 | |||
| 304 | for (object.comdat_groups.items) |cg_index| { | ||
| 305 | const cg = elf_file.comdatGroup(cg_index); | ||
| 306 | const cg_owner = elf_file.comdatGroupOwner(cg.owner); | ||
| 307 | if (cg_owner.file != index) continue; | ||
| 308 | |||
| 309 | const cg_sec = try elf_file.comdat_group_sections.addOne(gpa); | ||
| 310 | cg_sec.* = .{ | ||
| 311 | .shndx = try elf_file.addSection(.{ | ||
| 312 | .name = ".group", | ||
| 313 | .type = elf.SHT_GROUP, | ||
| 314 | .entsize = @sizeOf(u32), | ||
| 315 | .addralign = @alignOf(u32), | ||
| 316 | .offset = std.math.maxInt(u64), | ||
| 317 | }), | ||
| 318 | .cg_index = cg_index, | ||
| 319 | }; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | } | ||
| 323 | |||
| 324 | fn updateSectionSizes(elf_file: *Elf) !void { | ||
| 325 | for (elf_file.output_sections.keys(), elf_file.output_sections.values()) |shndx, atom_list| { | ||
| 326 | const shdr = &elf_file.shdrs.items[shndx]; | ||
| 327 | for (atom_list.items) |atom_index| { | ||
| 328 | const atom_ptr = elf_file.atom(atom_index) orelse continue; | ||
| 329 | if (!atom_ptr.flags.alive) continue; | ||
| 330 | const offset = atom_ptr.alignment.forward(shdr.sh_size); | ||
| 331 | const padding = offset - shdr.sh_size; | ||
| 332 | atom_ptr.value = offset; | ||
| 333 | shdr.sh_size += padding + atom_ptr.size; | ||
| 334 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1)); | ||
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | for (elf_file.output_rela_sections.values()) |sec| { | ||
| 339 | const shdr = &elf_file.shdrs.items[sec.shndx]; | ||
| 340 | for (sec.atom_list.items) |atom_index| { | ||
| 341 | const atom_ptr = elf_file.atom(atom_index) orelse continue; | ||
| 342 | if (!atom_ptr.flags.alive) continue; | ||
| 343 | const relocs = atom_ptr.relocs(elf_file); | ||
| 344 | shdr.sh_size += shdr.sh_entsize * relocs.len; | ||
| 345 | } | ||
| 346 | |||
| 347 | if (shdr.sh_size == 0) shdr.sh_offset = 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | if (elf_file.eh_frame_section_index) |index| { | ||
| 351 | elf_file.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(elf_file); | ||
| 352 | } | ||
| 353 | if (elf_file.eh_frame_rela_section_index) |index| { | ||
| 354 | const shdr = &elf_file.shdrs.items[index]; | ||
| 355 | shdr.sh_size = eh_frame.calcEhFrameRelocs(elf_file) * shdr.sh_entsize; | ||
| 356 | } | ||
| 357 | |||
| 358 | try elf_file.updateSymtabSize(); | ||
| 359 | updateComdatGroupsSizes(elf_file); | ||
| 360 | elf_file.updateShStrtabSize(); | ||
| 361 | } | ||
| 362 | |||
| 363 | fn updateComdatGroupsSizes(elf_file: *Elf) void { | ||
| 364 | for (elf_file.comdat_group_sections.items) |cg| { | ||
| 365 | const shdr = &elf_file.shdrs.items[cg.shndx]; | ||
| 366 | shdr.sh_size = cg.size(elf_file); | ||
| 367 | shdr.sh_link = elf_file.symtab_section_index.?; | ||
| 368 | |||
| 369 | const sym = elf_file.symbol(cg.symbol(elf_file)); | ||
| 370 | shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse | ||
| 371 | elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | /// Allocates alloc sections when merging relocatable objects files together. | ||
| 376 | fn allocateAllocSections(elf_file: *Elf) !void { | ||
| 377 | for (elf_file.shdrs.items) |*shdr| { | ||
| 378 | if (shdr.sh_type == elf.SHT_NULL) continue; | ||
| 379 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; | ||
| 380 | if (shdr.sh_type == elf.SHT_NOBITS) { | ||
| 381 | shdr.sh_offset = 0; | ||
| 382 | continue; | ||
| 383 | } | ||
| 384 | const needed_size = shdr.sh_size; | ||
| 385 | if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) { | ||
| 386 | shdr.sh_size = 0; | ||
| 387 | const new_offset = elf_file.findFreeSpace(needed_size, shdr.sh_addralign); | ||
| 388 | shdr.sh_offset = new_offset; | ||
| 389 | shdr.sh_size = needed_size; | ||
| 390 | } | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | fn writeAtoms(elf_file: *Elf) !void { | ||
| 395 | const gpa = elf_file.base.comp.gpa; | ||
| 396 | |||
| 397 | // TODO iterate over `output_sections` directly | ||
| 398 | for (elf_file.shdrs.items, 0..) |shdr, shndx| { | ||
| 399 | if (shdr.sh_type == elf.SHT_NULL) continue; | ||
| 400 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | ||
| 401 | |||
| 402 | const atom_list = elf_file.output_sections.get(@intCast(shndx)) orelse continue; | ||
| 403 | if (atom_list.items.len == 0) continue; | ||
| 404 | |||
| 405 | log.debug("writing atoms in '{s}' section", .{elf_file.getShString(shdr.sh_name)}); | ||
| 406 | |||
| 407 | // TODO really, really handle debug section separately | ||
| 408 | const base_offset = if (elf_file.isDebugSection(@intCast(shndx))) blk: { | ||
| 409 | const zig_object = elf_file.zigObjectPtr().?; | ||
| 410 | if (shndx == elf_file.debug_info_section_index.?) | ||
| 411 | break :blk zig_object.debug_info_section_zig_size; | ||
| 412 | if (shndx == elf_file.debug_abbrev_section_index.?) | ||
| 413 | break :blk zig_object.debug_abbrev_section_zig_size; | ||
| 414 | if (shndx == elf_file.debug_str_section_index.?) | ||
| 415 | break :blk zig_object.debug_str_section_zig_size; | ||
| 416 | if (shndx == elf_file.debug_aranges_section_index.?) | ||
| 417 | break :blk zig_object.debug_aranges_section_zig_size; | ||
| 418 | if (shndx == elf_file.debug_line_section_index.?) | ||
| 419 | break :blk zig_object.debug_line_section_zig_size; | ||
| 420 | unreachable; | ||
| 421 | } else 0; | ||
| 422 | const sh_offset = shdr.sh_offset + base_offset; | ||
| 423 | const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; | ||
| 424 | |||
| 425 | const buffer = try gpa.alloc(u8, sh_size); | ||
| 426 | defer gpa.free(buffer); | ||
| 427 | const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and | ||
| 428 | shdr.sh_flags & elf.SHF_EXECINSTR != 0) | ||
| 429 | 0xcc // int3 | ||
| 430 | else | ||
| 431 | 0; | ||
| 432 | @memset(buffer, padding_byte); | ||
| 433 | |||
| 434 | for (atom_list.items) |atom_index| { | ||
| 435 | const atom_ptr = elf_file.atom(atom_index).?; | ||
| 436 | assert(atom_ptr.flags.alive); | ||
| 437 | |||
| 438 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse | ||
| 439 | return error.Overflow; | ||
| 440 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | ||
| 441 | |||
| 442 | log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{ | ||
| 443 | atom_index, | ||
| 444 | sh_offset + offset, | ||
| 445 | sh_offset + offset + size, | ||
| 446 | }); | ||
| 447 | |||
| 448 | // TODO decompress directly into provided buffer | ||
| 449 | const out_code = buffer[offset..][0..size]; | ||
| 450 | const in_code = switch (atom_ptr.file(elf_file).?) { | ||
| 451 | .object => |x| try x.codeDecompressAlloc(elf_file, atom_index), | ||
| 452 | .zig_object => |x| try x.codeAlloc(elf_file, atom_index), | ||
| 453 | else => unreachable, | ||
| 454 | }; | ||
| 455 | defer gpa.free(in_code); | ||
| 456 | @memcpy(out_code, in_code); | ||
| 457 | } | ||
| 458 | |||
| 459 | try elf_file.base.file.?.pwriteAll(buffer, sh_offset); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | fn writeSyntheticSections(elf_file: *Elf) !void { | ||
| 464 | const gpa = elf_file.base.comp.gpa; | ||
| 465 | |||
| 466 | for (elf_file.output_rela_sections.values()) |sec| { | ||
| 467 | if (sec.atom_list.items.len == 0) continue; | ||
| 468 | |||
| 469 | const shdr = elf_file.shdrs.items[sec.shndx]; | ||
| 470 | |||
| 471 | const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse | ||
| 472 | return error.Overflow; | ||
| 473 | var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs); | ||
| 474 | defer relocs.deinit(); | ||
| 475 | |||
| 476 | for (sec.atom_list.items) |atom_index| { | ||
| 477 | const atom_ptr = elf_file.atom(atom_index) orelse continue; | ||
| 478 | if (!atom_ptr.flags.alive) continue; | ||
| 479 | try atom_ptr.writeRelocs(elf_file, &relocs); | ||
| 480 | } | ||
| 481 | assert(relocs.items.len == num_relocs); | ||
| 482 | |||
| 483 | const SortRelocs = struct { | ||
| 484 | pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { | ||
| 485 | _ = ctx; | ||
| 486 | return lhs.r_offset < rhs.r_offset; | ||
| 487 | } | ||
| 488 | }; | ||
| 489 | |||
| 490 | mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan); | ||
| 491 | |||
| 492 | log.debug("writing {s} from 0x{x} to 0x{x}", .{ | ||
| 493 | elf_file.getShString(shdr.sh_name), | ||
| 494 | shdr.sh_offset, | ||
| 495 | shdr.sh_offset + shdr.sh_size, | ||
| 496 | }); | ||
| 497 | |||
| 498 | try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); | ||
| 499 | } | ||
| 500 | |||
| 501 | if (elf_file.eh_frame_section_index) |shndx| { | ||
| 502 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 503 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 504 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); | ||
| 505 | defer buffer.deinit(); | ||
| 506 | try eh_frame.writeEhFrameObject(elf_file, buffer.writer()); | ||
| 507 | log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ | ||
| 508 | shdr.sh_offset, | ||
| 509 | shdr.sh_offset + shdr.sh_size, | ||
| 510 | }); | ||
| 511 | assert(buffer.items.len == sh_size); | ||
| 512 | try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 513 | } | ||
| 514 | if (elf_file.eh_frame_rela_section_index) |shndx| { | ||
| 515 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 516 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 517 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); | ||
| 518 | defer buffer.deinit(); | ||
| 519 | try eh_frame.writeEhFrameRelocs(elf_file, buffer.writer()); | ||
| 520 | assert(buffer.items.len == sh_size); | ||
| 521 | log.debug("writing .rela.eh_frame from 0x{x} to 0x{x}", .{ | ||
| 522 | shdr.sh_offset, | ||
| 523 | shdr.sh_offset + shdr.sh_size, | ||
| 524 | }); | ||
| 525 | try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 526 | } | ||
| 527 | |||
| 528 | try writeComdatGroups(elf_file); | ||
| 529 | try elf_file.writeSymtab(); | ||
| 530 | try elf_file.writeShStrtab(); | ||
| 531 | } | ||
| 532 | |||
| 533 | fn writeComdatGroups(elf_file: *Elf) !void { | ||
| 534 | const gpa = elf_file.base.comp.gpa; | ||
| 535 | for (elf_file.comdat_group_sections.items) |cgs| { | ||
| 536 | const shdr = elf_file.shdrs.items[cgs.shndx]; | ||
| 537 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | ||
| 538 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); | ||
| 539 | defer buffer.deinit(); | ||
| 540 | try cgs.write(elf_file, buffer.writer()); | ||
| 541 | assert(buffer.items.len == sh_size); | ||
| 542 | log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{ | ||
| 543 | shdr.sh_offset, | ||
| 544 | shdr.sh_offset + shdr.sh_size, | ||
| 545 | }); | ||
| 546 | try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 547 | } | ||
| 548 | } | ||
| 549 | |||
| 550 | const assert = std.debug.assert; | ||
| 551 | const build_options = @import("build_options"); | ||
| 552 | const eh_frame = @import("eh_frame.zig"); | ||
| 553 | const elf = std.elf; | ||
| 554 | const link = @import("../../link.zig"); | ||
| 555 | const log = std.log.scoped(.link); | ||
| 556 | const math = std.math; | ||
| 557 | const mem = std.mem; | ||
| 558 | const state_log = std.log.scoped(.link_state); | ||
| 559 | const std = @import("std"); | ||
| 560 | |||
| 561 | const Archive = @import("Archive.zig"); | ||
| 562 | const Compilation = @import("../../Compilation.zig"); | ||
| 563 | const Elf = @import("../Elf.zig"); | ||
| 564 | const File = @import("file.zig").File; | ||
| 565 | const Object = @import("Object.zig"); | ||
src/link/Elf/synthetic_sections.zig+2-3| ... | @@ -1582,15 +1582,14 @@ pub const ComdatGroupSection = struct { | ... | @@ -1582,15 +1582,14 @@ pub const ComdatGroupSection = struct { |
| 1582 | 1582 | ||
| 1583 | pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { | 1583 | pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize { |
| 1584 | const cg = elf_file.comdatGroup(cgs.cg_index); | 1584 | const cg = elf_file.comdatGroup(cgs.cg_index); |
| 1585 | const object = cgs.file(elf_file).?.object; | 1585 | const members = cg.comdatGroupMembers(elf_file); |
| 1586 | const members = object.comdatGroupMembers(cg.shndx); | ||
| 1587 | return (members.len + 1) * @sizeOf(u32); | 1586 | return (members.len + 1) * @sizeOf(u32); |
| 1588 | } | 1587 | } |
| 1589 | 1588 | ||
| 1590 | pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void { | 1589 | pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void { |
| 1591 | const cg = elf_file.comdatGroup(cgs.cg_index); | 1590 | const cg = elf_file.comdatGroup(cgs.cg_index); |
| 1592 | const object = cgs.file(elf_file).?.object; | 1591 | const object = cgs.file(elf_file).?.object; |
| 1593 | const members = object.comdatGroupMembers(cg.shndx); | 1592 | const members = cg.comdatGroupMembers(elf_file); |
| 1594 | try writer.writeInt(u32, elf.GRP_COMDAT, .little); | 1593 | try writer.writeInt(u32, elf.GRP_COMDAT, .little); |
| 1595 | for (members) |shndx| { | 1594 | for (members) |shndx| { |
| 1596 | const shdr = object.shdrs.items[shndx]; | 1595 | const shdr = object.shdrs.items[shndx]; |
src/link/MachO/Archive.zig+12-16| ... | @@ -24,20 +24,18 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: | ... | @@ -24,20 +24,18 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: |
| 24 | const handle = macho_file.getFileHandle(handle_index); | 24 | const handle = macho_file.getFileHandle(handle_index); |
| 25 | const offset = if (fat_arch) |ar| ar.offset else 0; | 25 | const offset = if (fat_arch) |ar| ar.offset else 0; |
| 26 | const size = if (fat_arch) |ar| ar.size else (try handle.stat()).size; | 26 | const size = if (fat_arch) |ar| ar.size else (try handle.stat()).size; |
| 27 | try handle.seekTo(offset); | ||
| 28 | 27 | ||
| 29 | const reader = handle.reader(); | 28 | var pos: usize = offset + SARMAG; |
| 30 | _ = try reader.readBytesNoEof(SARMAG); | ||
| 31 | |||
| 32 | var pos: usize = SARMAG; | ||
| 33 | while (true) { | 29 | while (true) { |
| 34 | if (pos >= size) break; | 30 | if (pos >= size) break; |
| 35 | if (!mem.isAligned(pos, 2)) { | 31 | if (!mem.isAligned(pos, 2)) pos += 1; |
| 36 | try handle.seekBy(1); | ||
| 37 | pos += 1; | ||
| 38 | } | ||
| 39 | 32 | ||
| 40 | const hdr = try reader.readStruct(ar_hdr); | 33 | var hdr_buffer: [@sizeOf(ar_hdr)]u8 = undefined; |
| 34 | { | ||
| 35 | const amt = try handle.preadAll(&hdr_buffer, pos); | ||
| 36 | if (amt != @sizeOf(ar_hdr)) return error.InputOutput; | ||
| 37 | } | ||
| 38 | const hdr = @as(*align(1) const ar_hdr, @ptrCast(&hdr_buffer)).*; | ||
| 41 | pos += @sizeOf(ar_hdr); | 39 | pos += @sizeOf(ar_hdr); |
| 42 | 40 | ||
| 43 | if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { | 41 | if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { |
| ... | @@ -53,17 +51,15 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: | ... | @@ -53,17 +51,15 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: |
| 53 | if (try hdr.nameLength()) |len| { | 51 | if (try hdr.nameLength()) |len| { |
| 54 | hdr_size -= len; | 52 | hdr_size -= len; |
| 55 | const buf = try arena.allocator().alloc(u8, len); | 53 | const buf = try arena.allocator().alloc(u8, len); |
| 56 | try reader.readNoEof(buf); | 54 | const amt = try handle.preadAll(buf, pos); |
| 55 | if (amt != len) return error.InputOutput; | ||
| 57 | pos += len; | 56 | pos += len; |
| 58 | const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; | 57 | const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; |
| 59 | break :name buf[0..actual_len]; | 58 | break :name buf[0..actual_len]; |
| 60 | } | 59 | } |
| 61 | unreachable; | 60 | unreachable; |
| 62 | }; | 61 | }; |
| 63 | defer { | 62 | defer pos += hdr_size; |
| 64 | _ = handle.seekBy(hdr_size) catch {}; | ||
| 65 | pos += hdr_size; | ||
| 66 | } | ||
| 67 | 63 | ||
| 68 | if (mem.eql(u8, name, SYMDEF) or | 64 | if (mem.eql(u8, name, SYMDEF) or |
| 69 | mem.eql(u8, name, SYMDEF64) or | 65 | mem.eql(u8, name, SYMDEF64) or |
| ... | @@ -73,7 +69,7 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: | ... | @@ -73,7 +69,7 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: |
| 73 | const object = Object{ | 69 | const object = Object{ |
| 74 | .archive = .{ | 70 | .archive = .{ |
| 75 | .path = try gpa.dupe(u8, path), | 71 | .path = try gpa.dupe(u8, path), |
| 76 | .offset = offset + pos, | 72 | .offset = pos, |
| 77 | }, | 73 | }, |
| 78 | .path = try gpa.dupe(u8, name), | 74 | .path = try gpa.dupe(u8, name), |
| 79 | .file_handle = handle_index, | 75 | .file_handle = handle_index, |