From b1930a3b57577e6a61582ae536943512ea31bcb6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Jan 2022 19:13:52 -0700 Subject: [PATCH] Elf: keep the logic for updates but condition on hcs --- src/link/Elf.zig | 64 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 4133892b6a91e03674a0d4b3d3518603a63ec106..c7ef9c698223468d3df033d9647a821c1bd6dd71 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2097,6 +2097,7 @@ fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { const phdr = &self.program_headers.items[block_list.phdr_index.?]; const shdr = &self.sections.items[block_list.section_index.?]; + const new_block_ideal_capacity = padToIdeal(new_block_size); // We use these to indicate our intention to update metadata, placing the new block, // and possibly removing a free list node. @@ -2109,7 +2110,42 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl // First we look for an appropriately sized free list node. // The list is unordered. We'll just take the first thing that works. const vaddr = blk: { - if (block_list.last_block) |last| { + var i: usize = if (self.base.child_pid == null) 0 else block_list.free_list.items.len; + while (i < block_list.free_list.items.len) { + const big_block = block_list.free_list.items[i]; + // We now have a pointer to a live text block that has too much capacity. + // Is it enough that we could fit this new text block? + const sym = self.local_symbols.items[big_block.local_sym_index]; + const capacity = big_block.capacity(self.*); + const ideal_capacity = padToIdeal(capacity); + const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; + const capacity_end_vaddr = sym.st_value + capacity; + const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; + const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); + if (new_start_vaddr < ideal_capacity_end_vaddr) { + // Additional bookkeeping here to notice if this free list node + // should be deleted because the block that it points to has grown to take up + // more of the extra capacity. + if (!big_block.freeListEligible(self.*)) { + _ = block_list.free_list.swapRemove(i); + } else { + i += 1; + } + continue; + } + // At this point we know that we will place the new block here. But the + // remaining question is whether there is still yet enough capacity left + // over for there to still be a free list node. + const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; + const keep_free_list_node = remaining_capacity >= min_text_capacity; + + // Set up the metadata to be updated, after errors are no longer possible. + block_placement = big_block; + if (!keep_free_list_node) { + free_list_removal = i; + } + break :blk new_start_vaddr; + } else if (block_list.last_block) |last| { const sym = self.local_symbols.items[last.local_sym_index]; const ideal_capacity = padToIdeal(sym.st_size); const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; @@ -2282,7 +2318,31 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; - { + if (local_sym.st_size != 0 and self.base.child_pid == null) { + const capacity = decl.link.elf.capacity(self.*); + const need_realloc = code.len > capacity or + !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); + if (need_realloc) { + const vaddr = try self.growTextBlock(block_list, &decl.link.elf, code.len, required_alignment); + log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr }); + if (vaddr != local_sym.st_value) { + local_sym.st_value = vaddr; + + log.debug(" (writing new offset table entry)", .{}); + self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; + try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); + } + } else if (code.len < local_sym.st_size) { + self.shrinkTextBlock(block_list, &decl.link.elf, code.len); + } + local_sym.st_size = code.len; + local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0)); + local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; + local_sym.st_other = 0; + local_sym.st_shndx = block_list.section_index.?; + // TODO this write could be avoided if no fields of the symbol were changed. + try self.writeSymbol(decl.link.elf.local_sym_index); + } else { const decl_name = mem.sliceTo(decl.name, 0); const name_str_index = try self.makeString(decl_name); const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); -- 2.54.0