authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 06:43:33+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 13:34:26+02:00
log801f038c2ced9c0d7147f4304834ac6ae68e4cb0
treecfbb49b2f0f6d3181ffc3c695874d29f62061782
parenteeec50d2515c5a3b65cab697ba3e28d89cc3b14c

elf: do not pad placeholders coming from input object files

This is currently not entirely accurate since no padding will affect the last-most atom of ZigObject that should be padded.

3 files changed, 30 insertions(+), 16 deletions(-)

src/link/Elf.zig+19-14
......@@ -659,12 +659,17 @@ const AllocateChunkResult = struct {
659659 placement: Ref,
660660};
661661
662pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignment) !AllocateChunkResult {
662pub fn allocateChunk(self: *Elf, args: struct {
663 size: u64,
664 shndx: u32,
665 alignment: Atom.Alignment,
666 requires_padding: bool = true,
667}) !AllocateChunkResult {
663668 const slice = self.sections.slice();
664 const shdr = &slice.items(.shdr)[shndx];
665 const free_list = &slice.items(.free_list)[shndx];
666 const last_atom_ref = &slice.items(.last_atom)[shndx];
667 const new_atom_ideal_capacity = padToIdeal(size);
669 const shdr = &slice.items(.shdr)[args.shndx];
670 const free_list = &slice.items(.free_list)[args.shndx];
671 const last_atom_ref = &slice.items(.last_atom)[args.shndx];
672 const new_atom_ideal_capacity = if (args.requires_padding) padToIdeal(args.size) else args.size;
668673
669674 // First we look for an appropriately sized free list node.
670675 // The list is unordered. We'll just take the first thing that works.
......@@ -676,11 +681,11 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen
676681 // We now have a pointer to a live atom that has too much capacity.
677682 // Is it enough that we could fit this new atom?
678683 const cap = big_atom.capacity(self);
679 const ideal_capacity = padToIdeal(cap);
684 const ideal_capacity = if (args.requires_padding) padToIdeal(cap) else cap;
680685 const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity;
681686 const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap;
682687 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
683 const new_start_vaddr = alignment.backward(new_start_vaddr_unaligned);
688 const new_start_vaddr = args.alignment.backward(new_start_vaddr_unaligned);
684689 if (new_start_vaddr < ideal_capacity_end_vaddr) {
685690 // Additional bookkeeping here to notice if this free list node
686691 // should be deleted because the block that it points to has grown to take up
......@@ -703,9 +708,9 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen
703708 }
704709 break :blk .{ .value = new_start_vaddr, .placement = big_atom_ref };
705710 } else if (self.atom(last_atom_ref.*)) |last_atom| {
706 const ideal_capacity = padToIdeal(last_atom.size);
711 const ideal_capacity = if (args.requires_padding) padToIdeal(last_atom.size) else last_atom.size;
707712 const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity;
708 const new_start_vaddr = alignment.forward(ideal_capacity_end_vaddr);
713 const new_start_vaddr = args.alignment.forward(ideal_capacity_end_vaddr);
709714 break :blk .{ .value = new_start_vaddr, .placement = last_atom.ref() };
710715 } else {
711716 break :blk .{ .value = 0, .placement = .{} };
......@@ -713,8 +718,8 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen
713718 };
714719
715720 log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{
716 size,
717 alignment.toByteUnits().?,
721 args.size,
722 args.alignment.toByteUnits().?,
718723 shdr.sh_addr + res.value,
719724 shdr.sh_offset + res.value,
720725 });
......@@ -724,11 +729,11 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen
724729 else
725730 true;
726731 if (expand_section) {
727 const needed_size = res.value + size;
732 const needed_size = res.value + args.size;
728733 if (shdr.sh_flags & elf.SHF_ALLOC != 0)
729 try self.growAllocSection(shndx, needed_size, alignment.toByteUnits().?)
734 try self.growAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?)
730735 else
731 try self.growNonAllocSection(shndx, needed_size, alignment.toByteUnits().?, true);
736 try self.growNonAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?, true);
732737 }
733738
734739 return res;
src/link/Elf/Object.zig+6-1
......@@ -969,7 +969,12 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void {
969969 }
970970
971971 for (self.section_chunks.items) |*chunk| {
972 const alloc_res = try elf_file.allocateChunk(chunk.output_section_index, chunk.size, chunk.alignment);
972 const alloc_res = try elf_file.allocateChunk(.{
973 .shndx = chunk.output_section_index,
974 .size = chunk.size,
975 .alignment = chunk.alignment,
976 .requires_padding = false,
977 });
973978 chunk.value = @intCast(alloc_res.value);
974979
975980 const slice = elf_file.sections.slice();
src/link/Elf/ZigObject.zig+5-1
......@@ -1996,7 +1996,11 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
19961996}
19971997
19981998fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
1999 const alloc_res = try elf_file.allocateChunk(atom_ptr.output_section_index, atom_ptr.size, atom_ptr.alignment);
1999 const alloc_res = try elf_file.allocateChunk(.{
2000 .shndx = atom_ptr.output_section_index,
2001 .size = atom_ptr.size,
2002 .alignment = atom_ptr.alignment,
2003 });
20002004 atom_ptr.value = @intCast(alloc_res.value);
20012005
20022006 const slice = elf_file.sections.slice();