| ... | ... | @@ -570,7 +570,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 570 | 570 | return null; |
| 571 | 571 | } |
| 572 | 572 | |
| 573 | | fn allocatedSize(self: *Elf, start: u64) u64 { |
| 573 | pub fn allocatedSize(self: *Elf, start: u64) u64 { |
| 574 | 574 | if (start == 0) return 0; |
| 575 | 575 | var min_pos: u64 = std.math.maxInt(u64); |
| 576 | 576 | if (self.shdr_table_offset) |off| { |
| ... | ... | @@ -597,7 +597,7 @@ fn allocatedVirtualSize(self: *Elf, start: u64) u64 { |
| 597 | 597 | return min_pos - start; |
| 598 | 598 | } |
| 599 | 599 | |
| 600 | | fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 600 | pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { |
| 601 | 601 | var start: u64 = 0; |
| 602 | 602 | while (self.detectAllocCollision(start, object_size)) |item_end| { |
| 603 | 603 | start = mem.alignForward(u64, item_end, min_alignment); |
| ... | ... | @@ -1083,8 +1083,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1083 | 1083 | }; |
| 1084 | 1084 | |
| 1085 | 1085 | if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); |
| 1086 | | if (self.base.isStaticLib()) return self.flushStaticLib(comp, module_obj_path); |
| 1087 | | if (self.base.isObject()) return self.flushObject(comp, module_obj_path); |
| 1086 | if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); |
| 1087 | if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); |
| 1088 | 1088 | |
| 1089 | 1089 | // Here we will parse input positional and library files (if referenced). |
| 1090 | 1090 | // This will roughly match in any linker backend we support. |
| ... | ... | @@ -1388,222 +1388,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) |
| 1388 | 1388 | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1389 | 1389 | } |
| 1390 | 1390 | |
| 1391 | | pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 1392 | | const gpa = comp.gpa; |
| 1393 | | |
| 1394 | | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); |
| 1395 | | defer positionals.deinit(); |
| 1396 | | |
| 1397 | | try positionals.ensureUnusedCapacity(comp.objects.len); |
| 1398 | | positionals.appendSliceAssumeCapacity(comp.objects); |
| 1399 | | |
| 1400 | | // This is a set of object files emitted by clang in a single `build-exe` invocation. |
| 1401 | | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up |
| 1402 | | // in this set. |
| 1403 | | for (comp.c_object_table.keys()) |key| { |
| 1404 | | try positionals.append(.{ .path = key.status.success.object_path }); |
| 1405 | | } |
| 1406 | | |
| 1407 | | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 1408 | | |
| 1409 | | for (positionals.items) |obj| { |
| 1410 | | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 1411 | | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported |
| 1412 | | else => |e| try self.reportParseError( |
| 1413 | | obj.path, |
| 1414 | | "unexpected error: parsing input file failed with error {s}", |
| 1415 | | .{@errorName(e)}, |
| 1416 | | ), |
| 1417 | | }; |
| 1418 | | } |
| 1419 | | |
| 1420 | | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1421 | | |
| 1422 | | // First, we flush relocatable object file generated with our backends. |
| 1423 | | if (self.zigObjectPtr()) |zig_object| { |
| 1424 | | zig_object.resolveSymbols(self); |
| 1425 | | zig_object.claimUnresolvedObject(self); |
| 1426 | | |
| 1427 | | try self.initSymtab(); |
| 1428 | | try self.initShStrtab(); |
| 1429 | | try self.sortShdrs(); |
| 1430 | | try zig_object.addAtomsToRelaSections(self); |
| 1431 | | try self.updateSectionSizesObject(); |
| 1432 | | |
| 1433 | | try self.allocateAllocSectionsObject(); |
| 1434 | | try self.allocateNonAllocSections(); |
| 1435 | | |
| 1436 | | if (build_options.enable_logging) { |
| 1437 | | state_log.debug("{}", .{self.dumpState()}); |
| 1438 | | } |
| 1439 | | |
| 1440 | | try self.writeSyntheticSectionsObject(); |
| 1441 | | try self.writeShdrTable(); |
| 1442 | | try self.writeElfHeader(); |
| 1443 | | |
| 1444 | | // TODO we can avoid reading in the file contents we just wrote if we give the linker |
| 1445 | | // ability to write directly to a buffer. |
| 1446 | | try zig_object.readFileContents(self); |
| 1447 | | } |
| 1448 | | |
| 1449 | | var files = std.ArrayList(File.Index).init(gpa); |
| 1450 | | defer files.deinit(); |
| 1451 | | try files.ensureTotalCapacityPrecise(self.objects.items.len + 1); |
| 1452 | | if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index); |
| 1453 | | for (self.objects.items) |index| files.appendAssumeCapacity(index); |
| 1454 | | |
| 1455 | | // Update ar symtab from parsed objects |
| 1456 | | var ar_symtab: Archive.ArSymtab = .{}; |
| 1457 | | defer ar_symtab.deinit(gpa); |
| 1458 | | |
| 1459 | | for (files.items) |index| { |
| 1460 | | try self.file(index).?.updateArSymtab(&ar_symtab, self); |
| 1461 | | } |
| 1462 | | |
| 1463 | | ar_symtab.sort(); |
| 1464 | | |
| 1465 | | // Save object paths in filenames strtab. |
| 1466 | | var ar_strtab: Archive.ArStrtab = .{}; |
| 1467 | | defer ar_strtab.deinit(gpa); |
| 1468 | | |
| 1469 | | for (files.items) |index| { |
| 1470 | | const file_ptr = self.file(index).?; |
| 1471 | | try file_ptr.updateArStrtab(gpa, &ar_strtab); |
| 1472 | | try file_ptr.updateArSize(self); |
| 1473 | | } |
| 1474 | | |
| 1475 | | // Update file offsets of contributing objects. |
| 1476 | | const total_size: usize = blk: { |
| 1477 | | var pos: usize = elf.ARMAG.len; |
| 1478 | | pos += @sizeOf(elf.ar_hdr) + ar_symtab.size(.p64); |
| 1479 | | |
| 1480 | | if (ar_strtab.size() > 0) { |
| 1481 | | pos = mem.alignForward(usize, pos, 2); |
| 1482 | | pos += @sizeOf(elf.ar_hdr) + ar_strtab.size(); |
| 1483 | | } |
| 1484 | | |
| 1485 | | for (files.items) |index| { |
| 1486 | | const file_ptr = self.file(index).?; |
| 1487 | | const state = switch (file_ptr) { |
| 1488 | | .zig_object => |x| &x.output_ar_state, |
| 1489 | | .object => |x| &x.output_ar_state, |
| 1490 | | else => unreachable, |
| 1491 | | }; |
| 1492 | | pos = mem.alignForward(usize, pos, 2); |
| 1493 | | state.file_off = pos; |
| 1494 | | pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow); |
| 1495 | | } |
| 1496 | | |
| 1497 | | break :blk pos; |
| 1498 | | }; |
| 1499 | | |
| 1500 | | if (build_options.enable_logging) { |
| 1501 | | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)}); |
| 1502 | | state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); |
| 1503 | | } |
| 1504 | | |
| 1505 | | var buffer = std.ArrayList(u8).init(gpa); |
| 1506 | | defer buffer.deinit(); |
| 1507 | | try buffer.ensureTotalCapacityPrecise(total_size); |
| 1508 | | |
| 1509 | | // Write magic |
| 1510 | | try buffer.writer().writeAll(elf.ARMAG); |
| 1511 | | |
| 1512 | | // Write symtab |
| 1513 | | try ar_symtab.write(.p64, self, buffer.writer()); |
| 1514 | | |
| 1515 | | // Write strtab |
| 1516 | | if (ar_strtab.size() > 0) { |
| 1517 | | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); |
| 1518 | | try ar_strtab.write(buffer.writer()); |
| 1519 | | } |
| 1520 | | |
| 1521 | | // Write object files |
| 1522 | | for (files.items) |index| { |
| 1523 | | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); |
| 1524 | | try self.file(index).?.writeAr(self, buffer.writer()); |
| 1525 | | } |
| 1526 | | |
| 1527 | | assert(buffer.items.len == total_size); |
| 1528 | | |
| 1529 | | try self.base.file.?.setEndPos(total_size); |
| 1530 | | try self.base.file.?.pwriteAll(buffer.items, 0); |
| 1531 | | |
| 1532 | | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1533 | | } |
| 1534 | | |
| 1535 | | pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 1536 | | const gpa = self.base.comp.gpa; |
| 1537 | | |
| 1538 | | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); |
| 1539 | | defer positionals.deinit(); |
| 1540 | | try positionals.ensureUnusedCapacity(comp.objects.len); |
| 1541 | | positionals.appendSliceAssumeCapacity(comp.objects); |
| 1542 | | |
| 1543 | | // This is a set of object files emitted by clang in a single `build-exe` invocation. |
| 1544 | | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up |
| 1545 | | // in this set. |
| 1546 | | for (comp.c_object_table.keys()) |key| { |
| 1547 | | try positionals.append(.{ .path = key.status.success.object_path }); |
| 1548 | | } |
| 1549 | | |
| 1550 | | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 1551 | | |
| 1552 | | for (positionals.items) |obj| { |
| 1553 | | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 1554 | | error.MalformedObject, error.MalformedArchive, error.InvalidCpuArch => continue, // already reported |
| 1555 | | else => |e| try self.reportParseError( |
| 1556 | | obj.path, |
| 1557 | | "unexpected error: parsing input file failed with error {s}", |
| 1558 | | .{@errorName(e)}, |
| 1559 | | ), |
| 1560 | | }; |
| 1561 | | } |
| 1562 | | |
| 1563 | | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1564 | | |
| 1565 | | // Init all objects |
| 1566 | | for (self.objects.items) |index| { |
| 1567 | | try self.file(index).?.object.init(self); |
| 1568 | | } |
| 1569 | | |
| 1570 | | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1571 | | |
| 1572 | | // Now, we are ready to resolve the symbols across all input files. |
| 1573 | | // We will first resolve the files in the ZigObject, next in the parsed |
| 1574 | | // input Object files. |
| 1575 | | self.resolveSymbols(); |
| 1576 | | self.markEhFrameAtomsDead(); |
| 1577 | | self.claimUnresolvedObject(); |
| 1578 | | |
| 1579 | | try self.initSectionsObject(); |
| 1580 | | try self.sortShdrs(); |
| 1581 | | if (self.zigObjectPtr()) |zig_object| { |
| 1582 | | try zig_object.addAtomsToRelaSections(self); |
| 1583 | | } |
| 1584 | | for (self.objects.items) |index| { |
| 1585 | | const object = self.file(index).?.object; |
| 1586 | | try object.addAtomsToOutputSections(self); |
| 1587 | | try object.addAtomsToRelaSections(self); |
| 1588 | | } |
| 1589 | | try self.updateSectionSizesObject(); |
| 1590 | | |
| 1591 | | try self.allocateAllocSectionsObject(); |
| 1592 | | try self.allocateNonAllocSections(); |
| 1593 | | self.allocateAtoms(); |
| 1594 | | |
| 1595 | | if (build_options.enable_logging) { |
| 1596 | | state_log.debug("{}", .{self.dumpState()}); |
| 1597 | | } |
| 1598 | | |
| 1599 | | try self.writeAtomsObject(); |
| 1600 | | try self.writeSyntheticSectionsObject(); |
| 1601 | | try self.writeShdrTable(); |
| 1602 | | try self.writeElfHeader(); |
| 1603 | | |
| 1604 | | if (comp.link_errors.items.len > 0) return error.FlushFailure; |
| 1605 | | } |
| 1606 | | |
| 1607 | 1391 | /// --verbose-link output |
| 1608 | 1392 | fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1609 | 1393 | const gpa = self.base.comp.gpa; |
| ... | ... | @@ -1880,7 +1664,7 @@ const ParseError = error{ |
| 1880 | 1664 | InvalidCharacter, |
| 1881 | 1665 | } || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError; |
| 1882 | 1666 | |
| 1883 | | fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void { |
| 1667 | pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void { |
| 1884 | 1668 | const tracy = trace(@src()); |
| 1885 | 1669 | defer tracy.end(); |
| 1886 | 1670 | if (try Object.isObject(path)) { |
| ... | ... | @@ -2089,7 +1873,7 @@ fn accessLibPath( |
| 2089 | 1873 | /// 4. Reset state of all resolved globals since we will redo this bit on the pruned set. |
| 2090 | 1874 | /// 5. Remove references to dead objects/shared objects |
| 2091 | 1875 | /// 6. Re-run symbol resolution on pruned objects and shared objects sets. |
| 2092 | | fn resolveSymbols(self: *Elf) void { |
| 1876 | pub fn resolveSymbols(self: *Elf) void { |
| 2093 | 1877 | // Resolve symbols in the ZigObject. For now, we assume that it's always live. |
| 2094 | 1878 | if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self); |
| 2095 | 1879 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). |
| ... | ... | @@ -2173,7 +1957,7 @@ fn markLive(self: *Elf) void { |
| 2173 | 1957 | } |
| 2174 | 1958 | } |
| 2175 | 1959 | |
| 2176 | | fn markEhFrameAtomsDead(self: *Elf) void { |
| 1960 | pub fn markEhFrameAtomsDead(self: *Elf) void { |
| 2177 | 1961 | for (self.objects.items) |index| { |
| 2178 | 1962 | const file_ptr = self.file(index).?; |
| 2179 | 1963 | if (!file_ptr.isAlive()) continue; |
| ... | ... | @@ -2239,15 +2023,6 @@ fn claimUnresolved(self: *Elf) void { |
| 2239 | 2023 | } |
| 2240 | 2024 | } |
| 2241 | 2025 | |
| 2242 | | fn claimUnresolvedObject(self: *Elf) void { |
| 2243 | | if (self.zigObjectPtr()) |zig_object| { |
| 2244 | | zig_object.claimUnresolvedObject(self); |
| 2245 | | } |
| 2246 | | for (self.objects.items) |index| { |
| 2247 | | self.file(index).?.object.claimUnresolvedObject(self); |
| 2248 | | } |
| 2249 | | } |
| 2250 | | |
| 2251 | 2026 | /// In scanRelocs we will go over all live atoms and scan their relocs. |
| 2252 | 2027 | /// This will help us work out what synthetics to emit, GOT indirection, etc. |
| 2253 | 2028 | /// This is also the point where we will report undefined symbols for any |
| ... | ... | @@ -2985,7 +2760,7 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) |
| 2985 | 2760 | } |
| 2986 | 2761 | } |
| 2987 | 2762 | |
| 2988 | | fn writeShdrTable(self: *Elf) !void { |
| 2763 | pub fn writeShdrTable(self: *Elf) !void { |
| 2989 | 2764 | const gpa = self.base.comp.gpa; |
| 2990 | 2765 | const target = self.base.comp.root_mod.resolved_target.result; |
| 2991 | 2766 | const target_endian = target.cpu.arch.endian(); |
| ... | ... | @@ -3082,7 +2857,7 @@ fn writePhdrTable(self: *Elf) !void { |
| 3082 | 2857 | } |
| 3083 | 2858 | } |
| 3084 | 2859 | |
| 3085 | | fn writeElfHeader(self: *Elf) !void { |
| 2860 | pub fn writeElfHeader(self: *Elf) !void { |
| 3086 | 2861 | const comp = self.base.comp; |
| 3087 | 2862 | if (comp.link_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable |
| 3088 | 2863 | |
| ... | ... | @@ -3658,61 +3433,7 @@ fn initSyntheticSections(self: *Elf) !void { |
| 3658 | 3433 | try self.initShStrtab(); |
| 3659 | 3434 | } |
| 3660 | 3435 | |
| 3661 | | fn initSectionsObject(self: *Elf) !void { |
| 3662 | | const ptr_size = self.ptrWidthBytes(); |
| 3663 | | |
| 3664 | | for (self.objects.items) |index| { |
| 3665 | | const object = self.file(index).?.object; |
| 3666 | | try object.initOutputSections(self); |
| 3667 | | try object.initRelaSections(self); |
| 3668 | | } |
| 3669 | | |
| 3670 | | const needs_eh_frame = for (self.objects.items) |index| { |
| 3671 | | if (self.file(index).?.object.cies.items.len > 0) break true; |
| 3672 | | } else false; |
| 3673 | | if (needs_eh_frame) { |
| 3674 | | self.eh_frame_section_index = try self.addSection(.{ |
| 3675 | | .name = ".eh_frame", |
| 3676 | | .type = elf.SHT_PROGBITS, |
| 3677 | | .flags = elf.SHF_ALLOC, |
| 3678 | | .addralign = ptr_size, |
| 3679 | | .offset = std.math.maxInt(u64), |
| 3680 | | }); |
| 3681 | | self.eh_frame_rela_section_index = try self.addRelaShdr(".rela.eh_frame", self.eh_frame_section_index.?); |
| 3682 | | } |
| 3683 | | |
| 3684 | | try self.initComdatGroups(); |
| 3685 | | try self.initSymtab(); |
| 3686 | | try self.initShStrtab(); |
| 3687 | | } |
| 3688 | | |
| 3689 | | fn initComdatGroups(self: *Elf) !void { |
| 3690 | | const gpa = self.base.comp.gpa; |
| 3691 | | |
| 3692 | | for (self.objects.items) |index| { |
| 3693 | | const object = self.file(index).?.object; |
| 3694 | | |
| 3695 | | for (object.comdat_groups.items) |cg_index| { |
| 3696 | | const cg = self.comdatGroup(cg_index); |
| 3697 | | const cg_owner = self.comdatGroupOwner(cg.owner); |
| 3698 | | if (cg_owner.file != index) continue; |
| 3699 | | |
| 3700 | | const cg_sec = try self.comdat_group_sections.addOne(gpa); |
| 3701 | | cg_sec.* = .{ |
| 3702 | | .shndx = try self.addSection(.{ |
| 3703 | | .name = ".group", |
| 3704 | | .type = elf.SHT_GROUP, |
| 3705 | | .entsize = @sizeOf(u32), |
| 3706 | | .addralign = @alignOf(u32), |
| 3707 | | .offset = std.math.maxInt(u64), |
| 3708 | | }), |
| 3709 | | .cg_index = cg_index, |
| 3710 | | }; |
| 3711 | | } |
| 3712 | | } |
| 3713 | | } |
| 3714 | | |
| 3715 | | fn initSymtab(self: *Elf) !void { |
| 3436 | pub fn initSymtab(self: *Elf) !void { |
| 3716 | 3437 | const small_ptr = switch (self.ptr_width) { |
| 3717 | 3438 | .p32 => true, |
| 3718 | 3439 | .p64 => false, |
| ... | ... | @@ -3737,7 +3458,7 @@ fn initSymtab(self: *Elf) !void { |
| 3737 | 3458 | } |
| 3738 | 3459 | } |
| 3739 | 3460 | |
| 3740 | | fn initShStrtab(self: *Elf) !void { |
| 3461 | pub fn initShStrtab(self: *Elf) !void { |
| 3741 | 3462 | if (self.shstrtab_section_index == null) { |
| 3742 | 3463 | self.shstrtab_section_index = try self.addSection(.{ |
| 3743 | 3464 | .name = ".shstrtab", |
| ... | ... | @@ -4043,7 +3764,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 { |
| 4043 | 3764 | } |
| 4044 | 3765 | } |
| 4045 | 3766 | |
| 4046 | | fn sortShdrs(self: *Elf) !void { |
| 3767 | pub fn sortShdrs(self: *Elf) !void { |
| 4047 | 3768 | const Entry = struct { |
| 4048 | 3769 | shndx: u16, |
| 4049 | 3770 | |
| ... | ... | @@ -4355,58 +4076,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4355 | 4076 | self.updateShStrtabSize(); |
| 4356 | 4077 | } |
| 4357 | 4078 | |
| 4358 | | fn updateSectionSizesObject(self: *Elf) !void { |
| 4359 | | for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { |
| 4360 | | const shdr = &self.shdrs.items[shndx]; |
| 4361 | | for (atom_list.items) |atom_index| { |
| 4362 | | const atom_ptr = self.atom(atom_index) orelse continue; |
| 4363 | | if (!atom_ptr.flags.alive) continue; |
| 4364 | | const offset = atom_ptr.alignment.forward(shdr.sh_size); |
| 4365 | | const padding = offset - shdr.sh_size; |
| 4366 | | atom_ptr.value = offset; |
| 4367 | | shdr.sh_size += padding + atom_ptr.size; |
| 4368 | | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1)); |
| 4369 | | } |
| 4370 | | } |
| 4371 | | |
| 4372 | | for (self.output_rela_sections.values()) |sec| { |
| 4373 | | const shdr = &self.shdrs.items[sec.shndx]; |
| 4374 | | for (sec.atom_list.items) |atom_index| { |
| 4375 | | const atom_ptr = self.atom(atom_index) orelse continue; |
| 4376 | | if (!atom_ptr.flags.alive) continue; |
| 4377 | | const relocs = atom_ptr.relocs(self); |
| 4378 | | shdr.sh_size += shdr.sh_entsize * relocs.len; |
| 4379 | | } |
| 4380 | | |
| 4381 | | if (shdr.sh_size == 0) shdr.sh_offset = 0; |
| 4382 | | } |
| 4383 | | |
| 4384 | | if (self.eh_frame_section_index) |index| { |
| 4385 | | self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); |
| 4386 | | } |
| 4387 | | if (self.eh_frame_rela_section_index) |index| { |
| 4388 | | const shdr = &self.shdrs.items[index]; |
| 4389 | | shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize; |
| 4390 | | } |
| 4391 | | |
| 4392 | | try self.updateSymtabSize(); |
| 4393 | | self.updateComdatGroupsSizes(); |
| 4394 | | self.updateShStrtabSize(); |
| 4395 | | } |
| 4396 | | |
| 4397 | | fn updateComdatGroupsSizes(self: *Elf) void { |
| 4398 | | for (self.comdat_group_sections.items) |cg| { |
| 4399 | | const shdr = &self.shdrs.items[cg.shndx]; |
| 4400 | | shdr.sh_size = cg.size(self); |
| 4401 | | shdr.sh_link = self.symtab_section_index.?; |
| 4402 | | |
| 4403 | | const sym = self.symbol(cg.symbol(self)); |
| 4404 | | shdr.sh_info = sym.outputSymtabIndex(self) orelse |
| 4405 | | self.sectionSymbolOutputSymtabIndex(sym.outputShndx().?); |
| 4406 | | } |
| 4407 | | } |
| 4408 | | |
| 4409 | | fn updateShStrtabSize(self: *Elf) void { |
| 4079 | pub fn updateShStrtabSize(self: *Elf) void { |
| 4410 | 4080 | if (self.shstrtab_section_index) |index| { |
| 4411 | 4081 | self.shdrs.items[index].sh_size = self.shstrtab.items.len; |
| 4412 | 4082 | } |
| ... | ... | @@ -4491,7 +4161,7 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { |
| 4491 | 4161 | |
| 4492 | 4162 | /// Allocates alloc sections and creates load segments for sections |
| 4493 | 4163 | /// extracted from input object files. |
| 4494 | | fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4164 | pub fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4495 | 4165 | // We use this struct to track maximum alignment of all TLS sections. |
| 4496 | 4166 | // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold, |
| 4497 | 4167 | // in-file offsets have to be aligned against the start of TLS program header. |
| ... | ... | @@ -4638,27 +4308,8 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4638 | 4308 | } |
| 4639 | 4309 | } |
| 4640 | 4310 | |
| 4641 | | /// Allocates alloc sections when merging relocatable objects files together. |
| 4642 | | fn allocateAllocSectionsObject(self: *Elf) !void { |
| 4643 | | for (self.shdrs.items) |*shdr| { |
| 4644 | | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4645 | | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4646 | | if (shdr.sh_type == elf.SHT_NOBITS) { |
| 4647 | | shdr.sh_offset = 0; |
| 4648 | | continue; |
| 4649 | | } |
| 4650 | | const needed_size = shdr.sh_size; |
| 4651 | | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 4652 | | shdr.sh_size = 0; |
| 4653 | | const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign); |
| 4654 | | shdr.sh_offset = new_offset; |
| 4655 | | shdr.sh_size = needed_size; |
| 4656 | | } |
| 4657 | | } |
| 4658 | | } |
| 4659 | | |
| 4660 | 4311 | /// Allocates non-alloc sections (debug info, symtabs, etc.). |
| 4661 | | fn allocateNonAllocSections(self: *Elf) !void { |
| 4312 | pub fn allocateNonAllocSections(self: *Elf) !void { |
| 4662 | 4313 | for (self.shdrs.items, 0..) |*shdr, shndx| { |
| 4663 | 4314 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4664 | 4315 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) continue; |
| ... | ... | @@ -4757,7 +4408,7 @@ fn allocateSpecialPhdrs(self: *Elf) void { |
| 4757 | 4408 | } |
| 4758 | 4409 | } |
| 4759 | 4410 | |
| 4760 | | fn allocateAtoms(self: *Elf) void { |
| 4411 | pub fn allocateAtoms(self: *Elf) void { |
| 4761 | 4412 | if (self.zigObjectPtr()) |zig_object| { |
| 4762 | 4413 | zig_object.allocateTlvAtoms(self); |
| 4763 | 4414 | } |
| ... | ... | @@ -4854,76 +4505,7 @@ fn writeAtoms(self: *Elf) !void { |
| 4854 | 4505 | try self.reportUndefinedSymbols(&undefs); |
| 4855 | 4506 | } |
| 4856 | 4507 | |
| 4857 | | fn writeAtomsObject(self: *Elf) !void { |
| 4858 | | const gpa = self.base.comp.gpa; |
| 4859 | | |
| 4860 | | // TODO iterate over `output_sections` directly |
| 4861 | | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 4862 | | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4863 | | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 4864 | | |
| 4865 | | const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue; |
| 4866 | | if (atom_list.items.len == 0) continue; |
| 4867 | | |
| 4868 | | log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); |
| 4869 | | |
| 4870 | | // TODO really, really handle debug section separately |
| 4871 | | const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: { |
| 4872 | | const zig_object = self.zigObjectPtr().?; |
| 4873 | | if (shndx == self.debug_info_section_index.?) |
| 4874 | | break :blk zig_object.debug_info_section_zig_size; |
| 4875 | | if (shndx == self.debug_abbrev_section_index.?) |
| 4876 | | break :blk zig_object.debug_abbrev_section_zig_size; |
| 4877 | | if (shndx == self.debug_str_section_index.?) |
| 4878 | | break :blk zig_object.debug_str_section_zig_size; |
| 4879 | | if (shndx == self.debug_aranges_section_index.?) |
| 4880 | | break :blk zig_object.debug_aranges_section_zig_size; |
| 4881 | | if (shndx == self.debug_line_section_index.?) |
| 4882 | | break :blk zig_object.debug_line_section_zig_size; |
| 4883 | | unreachable; |
| 4884 | | } else 0; |
| 4885 | | const sh_offset = shdr.sh_offset + base_offset; |
| 4886 | | const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; |
| 4887 | | |
| 4888 | | const buffer = try gpa.alloc(u8, sh_size); |
| 4889 | | defer gpa.free(buffer); |
| 4890 | | const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and |
| 4891 | | shdr.sh_flags & elf.SHF_EXECINSTR != 0) |
| 4892 | | 0xcc // int3 |
| 4893 | | else |
| 4894 | | 0; |
| 4895 | | @memset(buffer, padding_byte); |
| 4896 | | |
| 4897 | | for (atom_list.items) |atom_index| { |
| 4898 | | const atom_ptr = self.atom(atom_index).?; |
| 4899 | | assert(atom_ptr.flags.alive); |
| 4900 | | |
| 4901 | | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse |
| 4902 | | return error.Overflow; |
| 4903 | | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 4904 | | |
| 4905 | | log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{ |
| 4906 | | atom_index, |
| 4907 | | sh_offset + offset, |
| 4908 | | sh_offset + offset + size, |
| 4909 | | }); |
| 4910 | | |
| 4911 | | // TODO decompress directly into provided buffer |
| 4912 | | const out_code = buffer[offset..][0..size]; |
| 4913 | | const in_code = switch (atom_ptr.file(self).?) { |
| 4914 | | .object => |x| try x.codeDecompressAlloc(self, atom_index), |
| 4915 | | .zig_object => |x| try x.codeAlloc(self, atom_index), |
| 4916 | | else => unreachable, |
| 4917 | | }; |
| 4918 | | defer gpa.free(in_code); |
| 4919 | | @memcpy(out_code, in_code); |
| 4920 | | } |
| 4921 | | |
| 4922 | | try self.base.file.?.pwriteAll(buffer, sh_offset); |
| 4923 | | } |
| 4924 | | } |
| 4925 | | |
| 4926 | | fn updateSymtabSize(self: *Elf) !void { |
| 4508 | pub fn updateSymtabSize(self: *Elf) !void { |
| 4927 | 4509 | var nlocals: u32 = 0; |
| 4928 | 4510 | var nglobals: u32 = 0; |
| 4929 | 4511 | var strsize: u32 = 0; |
| ... | ... | @@ -5141,94 +4723,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 5141 | 4723 | try self.writeShStrtab(); |
| 5142 | 4724 | } |
| 5143 | 4725 | |
| 5144 | | fn writeSyntheticSectionsObject(self: *Elf) !void { |
| 5145 | | const gpa = self.base.comp.gpa; |
| 5146 | | |
| 5147 | | for (self.output_rela_sections.values()) |sec| { |
| 5148 | | if (sec.atom_list.items.len == 0) continue; |
| 5149 | | |
| 5150 | | const shdr = self.shdrs.items[sec.shndx]; |
| 5151 | | |
| 5152 | | const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse |
| 5153 | | return error.Overflow; |
| 5154 | | var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs); |
| 5155 | | defer relocs.deinit(); |
| 5156 | | |
| 5157 | | for (sec.atom_list.items) |atom_index| { |
| 5158 | | const atom_ptr = self.atom(atom_index) orelse continue; |
| 5159 | | if (!atom_ptr.flags.alive) continue; |
| 5160 | | try atom_ptr.writeRelocs(self, &relocs); |
| 5161 | | } |
| 5162 | | assert(relocs.items.len == num_relocs); |
| 5163 | | |
| 5164 | | const SortRelocs = struct { |
| 5165 | | pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { |
| 5166 | | _ = ctx; |
| 5167 | | return lhs.r_offset < rhs.r_offset; |
| 5168 | | } |
| 5169 | | }; |
| 5170 | | |
| 5171 | | mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan); |
| 5172 | | |
| 5173 | | log.debug("writing {s} from 0x{x} to 0x{x}", .{ |
| 5174 | | self.getShString(shdr.sh_name), |
| 5175 | | shdr.sh_offset, |
| 5176 | | shdr.sh_offset + shdr.sh_size, |
| 5177 | | }); |
| 5178 | | |
| 5179 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); |
| 5180 | | } |
| 5181 | | |
| 5182 | | if (self.eh_frame_section_index) |shndx| { |
| 5183 | | const shdr = self.shdrs.items[shndx]; |
| 5184 | | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 5185 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 5186 | | defer buffer.deinit(); |
| 5187 | | try eh_frame.writeEhFrameObject(self, buffer.writer()); |
| 5188 | | log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ |
| 5189 | | shdr.sh_offset, |
| 5190 | | shdr.sh_offset + shdr.sh_size, |
| 5191 | | }); |
| 5192 | | assert(buffer.items.len == sh_size); |
| 5193 | | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 5194 | | } |
| 5195 | | if (self.eh_frame_rela_section_index) |shndx| { |
| 5196 | | const shdr = self.shdrs.items[shndx]; |
| 5197 | | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 5198 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 5199 | | defer buffer.deinit(); |
| 5200 | | try eh_frame.writeEhFrameRelocs(self, buffer.writer()); |
| 5201 | | assert(buffer.items.len == sh_size); |
| 5202 | | log.debug("writing .rela.eh_frame from 0x{x} to 0x{x}", .{ |
| 5203 | | shdr.sh_offset, |
| 5204 | | shdr.sh_offset + shdr.sh_size, |
| 5205 | | }); |
| 5206 | | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 5207 | | } |
| 5208 | | |
| 5209 | | try self.writeComdatGroups(); |
| 5210 | | try self.writeSymtab(); |
| 5211 | | try self.writeShStrtab(); |
| 5212 | | } |
| 5213 | | |
| 5214 | | fn writeComdatGroups(self: *Elf) !void { |
| 5215 | | const gpa = self.base.comp.gpa; |
| 5216 | | for (self.comdat_group_sections.items) |cgs| { |
| 5217 | | const shdr = self.shdrs.items[cgs.shndx]; |
| 5218 | | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 5219 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 5220 | | defer buffer.deinit(); |
| 5221 | | try cgs.write(self, buffer.writer()); |
| 5222 | | assert(buffer.items.len == sh_size); |
| 5223 | | log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{ |
| 5224 | | shdr.sh_offset, |
| 5225 | | shdr.sh_offset + shdr.sh_size, |
| 5226 | | }); |
| 5227 | | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 5228 | | } |
| 5229 | | } |
| 5230 | | |
| 5231 | | fn writeShStrtab(self: *Elf) !void { |
| 4726 | pub fn writeShStrtab(self: *Elf) !void { |
| 5232 | 4727 | if (self.shstrtab_section_index) |index| { |
| 5233 | 4728 | const shdr = self.shdrs.items[index]; |
| 5234 | 4729 | log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size }); |
| ... | ... | @@ -5236,7 +4731,7 @@ fn writeShStrtab(self: *Elf) !void { |
| 5236 | 4731 | } |
| 5237 | 4732 | } |
| 5238 | 4733 | |
| 5239 | | fn writeSymtab(self: *Elf) !void { |
| 4734 | pub fn writeSymtab(self: *Elf) !void { |
| 5240 | 4735 | const target = self.base.comp.root_mod.resolved_target.result; |
| 5241 | 4736 | const gpa = self.base.comp.gpa; |
| 5242 | 4737 | const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; |
| ... | ... | @@ -5367,7 +4862,7 @@ pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { |
| 5367 | 4862 | } |
| 5368 | 4863 | |
| 5369 | 4864 | /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF. |
| 5370 | | fn ptrWidthBytes(self: Elf) u8 { |
| 4865 | pub fn ptrWidthBytes(self: Elf) u8 { |
| 5371 | 4866 | return switch (self.ptr_width) { |
| 5372 | 4867 | .p32 => 4, |
| 5373 | 4868 | .p64 => 8, |
| ... | ... | @@ -5713,7 +5208,7 @@ fn addPhdr(self: *Elf, opts: struct { |
| 5713 | 5208 | return index; |
| 5714 | 5209 | } |
| 5715 | 5210 | |
| 5716 | | fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 { |
| 5211 | pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 { |
| 5717 | 5212 | const entsize: u64 = switch (self.ptr_width) { |
| 5718 | 5213 | .p32 => @sizeOf(elf.Elf32_Rela), |
| 5719 | 5214 | .p64 => @sizeOf(elf.Elf64_Rela), |
| ... | ... | @@ -6340,7 +5835,7 @@ fn formatPhdr( |
| 6340 | 5835 | }); |
| 6341 | 5836 | } |
| 6342 | 5837 | |
| 6343 | | fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { |
| 5838 | pub fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) { |
| 6344 | 5839 | return .{ .data = self }; |
| 6345 | 5840 | } |
| 6346 | 5841 | |
| ... | ... | @@ -6579,6 +6074,7 @@ const glibc = @import("../glibc.zig"); |
| 6579 | 6074 | const link = @import("../link.zig"); |
| 6580 | 6075 | const lldMain = @import("../main.zig").lldMain; |
| 6581 | 6076 | const musl = @import("../musl.zig"); |
| 6077 | const relocatable = @import("Elf/relocatable.zig"); |
| 6582 | 6078 | const target_util = @import("../target.zig"); |
| 6583 | 6079 | const trace = @import("../tracy.zig").trace; |
| 6584 | 6080 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); |