| ... | @@ -2097,6 +2097,7 @@ fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, | ... | @@ -2097,6 +2097,7 @@ fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, |
| 2097 | fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 2097 | fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 2098 | const phdr = &self.program_headers.items[block_list.phdr_index.?]; | 2098 | const phdr = &self.program_headers.items[block_list.phdr_index.?]; |
| 2099 | const shdr = &self.sections.items[block_list.section_index.?]; | 2099 | const shdr = &self.sections.items[block_list.section_index.?]; |
| | 2100 | const new_block_ideal_capacity = padToIdeal(new_block_size); |
| 2100 | | 2101 | |
| 2101 | // We use these to indicate our intention to update metadata, placing the new block, | 2102 | // We use these to indicate our intention to update metadata, placing the new block, |
| 2102 | // and possibly removing a free list node. | 2103 | // and possibly removing a free list node. |
| ... | @@ -2109,7 +2110,42 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl | ... | @@ -2109,7 +2110,42 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2109 | // First we look for an appropriately sized free list node. | 2110 | // First we look for an appropriately sized free list node. |
| 2110 | // The list is unordered. We'll just take the first thing that works. | 2111 | // The list is unordered. We'll just take the first thing that works. |
| 2111 | const vaddr = blk: { | 2112 | const vaddr = blk: { |
| 2112 | if (block_list.last_block) |last| { | 2113 | var i: usize = if (self.base.child_pid == null) 0 else block_list.free_list.items.len; |
| | 2114 | while (i < block_list.free_list.items.len) { |
| | 2115 | const big_block = block_list.free_list.items[i]; |
| | 2116 | // We now have a pointer to a live text block that has too much capacity. |
| | 2117 | // Is it enough that we could fit this new text block? |
| | 2118 | const sym = self.local_symbols.items[big_block.local_sym_index]; |
| | 2119 | const capacity = big_block.capacity(self.*); |
| | 2120 | const ideal_capacity = padToIdeal(capacity); |
| | 2121 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; |
| | 2122 | const capacity_end_vaddr = sym.st_value + capacity; |
| | 2123 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; |
| | 2124 | const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); |
| | 2125 | if (new_start_vaddr < ideal_capacity_end_vaddr) { |
| | 2126 | // Additional bookkeeping here to notice if this free list node |
| | 2127 | // should be deleted because the block that it points to has grown to take up |
| | 2128 | // more of the extra capacity. |
| | 2129 | if (!big_block.freeListEligible(self.*)) { |
| | 2130 | _ = block_list.free_list.swapRemove(i); |
| | 2131 | } else { |
| | 2132 | i += 1; |
| | 2133 | } |
| | 2134 | continue; |
| | 2135 | } |
| | 2136 | // At this point we know that we will place the new block here. But the |
| | 2137 | // remaining question is whether there is still yet enough capacity left |
| | 2138 | // over for there to still be a free list node. |
| | 2139 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; |
| | 2140 | const keep_free_list_node = remaining_capacity >= min_text_capacity; |
| | 2141 | |
| | 2142 | // Set up the metadata to be updated, after errors are no longer possible. |
| | 2143 | block_placement = big_block; |
| | 2144 | if (!keep_free_list_node) { |
| | 2145 | free_list_removal = i; |
| | 2146 | } |
| | 2147 | break :blk new_start_vaddr; |
| | 2148 | } else if (block_list.last_block) |last| { |
| 2113 | const sym = self.local_symbols.items[last.local_sym_index]; | 2149 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2114 | const ideal_capacity = padToIdeal(sym.st_size); | 2150 | const ideal_capacity = padToIdeal(sym.st_size); |
| 2115 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | 2151 | 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 | ... | @@ -2282,7 +2318,31 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2282 | | 2318 | |
| 2283 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() | 2319 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 2284 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; | 2320 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 2285 | { | 2321 | if (local_sym.st_size != 0 and self.base.child_pid == null) { |
| | 2322 | const capacity = decl.link.elf.capacity(self.*); |
| | 2323 | const need_realloc = code.len > capacity or |
| | 2324 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); |
| | 2325 | if (need_realloc) { |
| | 2326 | const vaddr = try self.growTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |
| | 2327 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr }); |
| | 2328 | if (vaddr != local_sym.st_value) { |
| | 2329 | local_sym.st_value = vaddr; |
| | 2330 | |
| | 2331 | log.debug(" (writing new offset table entry)", .{}); |
| | 2332 | self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; |
| | 2333 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); |
| | 2334 | } |
| | 2335 | } else if (code.len < local_sym.st_size) { |
| | 2336 | self.shrinkTextBlock(block_list, &decl.link.elf, code.len); |
| | 2337 | } |
| | 2338 | local_sym.st_size = code.len; |
| | 2339 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0)); |
| | 2340 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; |
| | 2341 | local_sym.st_other = 0; |
| | 2342 | local_sym.st_shndx = block_list.section_index.?; |
| | 2343 | // TODO this write could be avoided if no fields of the symbol were changed. |
| | 2344 | try self.writeSymbol(decl.link.elf.local_sym_index); |
| | 2345 | } else { |
| 2286 | const decl_name = mem.sliceTo(decl.name, 0); | 2346 | const decl_name = mem.sliceTo(decl.name, 0); |
| 2287 | const name_str_index = try self.makeString(decl_name); | 2347 | const name_str_index = try self.makeString(decl_name); |
| 2288 | const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); | 2348 | const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |