| ... | ... | @@ -56,6 +56,11 @@ phdr_load_re_index: ?u16 = null, |
| 56 | 56 | phdr_got_index: ?u16 = null, |
| 57 | 57 | /// The index into the program headers of a PT_LOAD program header with Read flag |
| 58 | 58 | phdr_load_ro_index: ?u16 = null, |
| 59 | /// The index into the program headers of a PT_LOAD program header with Write flag |
| 60 | phdr_load_rw_index: ?u16 = null, |
| 61 | |
| 62 | phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{}, |
| 63 | |
| 59 | 64 | entry_addr: ?u64 = null, |
| 60 | 65 | |
| 61 | 66 | debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, |
| ... | ... | @@ -63,7 +68,10 @@ shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, |
| 63 | 68 | shstrtab_index: ?u16 = null, |
| 64 | 69 | |
| 65 | 70 | symtab_section_index: ?u16 = null, |
| 71 | text_section_index: ?u16 = null, |
| 72 | rodata_section_index: ?u16 = null, |
| 66 | 73 | got_section_index: ?u16 = null, |
| 74 | data_section_index: ?u16 = null, |
| 67 | 75 | debug_info_section_index: ?u16 = null, |
| 68 | 76 | debug_abbrev_section_index: ?u16 = null, |
| 69 | 77 | debug_str_section_index: ?u16 = null, |
| ... | ... | @@ -116,8 +124,9 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 116 | 124 | /// overcapacity can be negative. A simple way to have negative overcapacity is to |
| 117 | 125 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 118 | 126 | /// by 1 byte. It will then have -1 overcapacity. |
| 119 | | text_block_list: TextBlockList = .{}, |
| 120 | | rodata_block_list: TextBlockList = .{}, |
| 127 | atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{}, |
| 128 | atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{}, |
| 129 | decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{}, |
| 121 | 130 | |
| 122 | 131 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. |
| 123 | 132 | /// This is the same concept as `text_block_free_list`; see those doc comments. |
| ... | ... | @@ -205,14 +214,6 @@ pub const TextBlock = struct { |
| 205 | 214 | } |
| 206 | 215 | }; |
| 207 | 216 | |
| 208 | | /// A list of text blocks in a specific section |
| 209 | | const TextBlockList = struct { |
| 210 | | free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 211 | | last_block: ?*TextBlock = null, |
| 212 | | phdr_index: ?u16 = null, |
| 213 | | section_index: ?u16 = null, |
| 214 | | }; |
| 215 | | |
| 216 | 217 | pub const Export = struct { |
| 217 | 218 | sym_index: ?u32 = null, |
| 218 | 219 | }; |
| ... | ... | @@ -326,11 +327,20 @@ pub fn deinit(self: *Elf) void { |
| 326 | 327 | self.global_symbol_free_list.deinit(self.base.allocator); |
| 327 | 328 | self.local_symbol_free_list.deinit(self.base.allocator); |
| 328 | 329 | self.offset_table_free_list.deinit(self.base.allocator); |
| 329 | | self.text_block_list.free_list.deinit(self.base.allocator); |
| 330 | | self.rodata_block_list.free_list.deinit(self.base.allocator); |
| 331 | 330 | self.dbg_line_fn_free_list.deinit(self.base.allocator); |
| 332 | 331 | self.dbg_info_decl_free_list.deinit(self.base.allocator); |
| 333 | 332 | self.offset_table.deinit(self.base.allocator); |
| 333 | self.phdr_shdr_table.deinit(self.base.allocator); |
| 334 | self.decls.deinit(self.base.allocator); |
| 335 | |
| 336 | self.atoms.deinit(self.base.allocator); |
| 337 | { |
| 338 | var it = self.atom_free_lists.valueIterator(); |
| 339 | while (it.next()) |free_list| { |
| 340 | free_list.deinit(self.base.allocator); |
| 341 | } |
| 342 | self.atom_free_lists.deinit(self.base.allocator); |
| 343 | } |
| 334 | 344 | } |
| 335 | 345 | |
| 336 | 346 | pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 { |
| ... | ... | @@ -463,11 +473,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 463 | 473 | const ptr_size: u8 = self.ptrWidthBytes(); |
| 464 | 474 | if (self.phdr_load_re_index == null) { |
| 465 | 475 | self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); |
| 466 | | self.text_block_list.phdr_index = self.phdr_load_re_index; |
| 467 | 476 | const file_size = self.base.options.program_code_size_hint; |
| 468 | 477 | const p_align = 0x1000; |
| 469 | 478 | const off = self.findFreeSpace(file_size, p_align); |
| 470 | | log.debug("found PT_LOAD free space 0x{x} to 0x{x}", .{ off, off + file_size }); |
| 479 | log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size }); |
| 471 | 480 | const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr; |
| 472 | 481 | try self.program_headers.append(self.base.allocator, .{ |
| 473 | 482 | .p_type = elf.PT_LOAD, |
| ... | ... | @@ -479,6 +488,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 479 | 488 | .p_align = p_align, |
| 480 | 489 | .p_flags = elf.PF_X | elf.PF_R, |
| 481 | 490 | }); |
| 491 | try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_re_index.?, .{}); |
| 482 | 492 | self.entry_addr = null; |
| 483 | 493 | self.phdr_table_dirty = true; |
| 484 | 494 | } |
| ... | ... | @@ -489,7 +499,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 489 | 499 | // page align. |
| 490 | 500 | const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); |
| 491 | 501 | const off = self.findFreeSpace(file_size, p_align); |
| 492 | | log.debug("found PT_LOAD free space 0x{x} to 0x{x}", .{ off, off + file_size }); |
| 502 | log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size }); |
| 493 | 503 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. |
| 494 | 504 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something |
| 495 | 505 | // else in virtual memory. |
| ... | ... | @@ -508,15 +518,14 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 508 | 518 | } |
| 509 | 519 | if (self.phdr_load_ro_index == null) { |
| 510 | 520 | self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len); |
| 511 | | self.rodata_block_list.phdr_index = self.phdr_load_ro_index; |
| 512 | 521 | // TODO Find a hint about how much data need to be in rodata ? |
| 513 | 522 | const file_size = 1024; |
| 514 | 523 | // Same reason as for GOT |
| 515 | 524 | const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); |
| 516 | 525 | const off = self.findFreeSpace(file_size, p_align); |
| 517 | | log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 526 | log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 518 | 527 | // TODO Same as for GOT |
| 519 | | const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x6000000 else 0xD000; |
| 528 | const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x5000000 else 0xa000; |
| 520 | 529 | try self.program_headers.append(self.base.allocator, .{ |
| 521 | 530 | .p_type = elf.PT_LOAD, |
| 522 | 531 | .p_offset = off, |
| ... | ... | @@ -527,6 +536,30 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 527 | 536 | .p_align = p_align, |
| 528 | 537 | .p_flags = elf.PF_R, |
| 529 | 538 | }); |
| 539 | try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{}); |
| 540 | self.phdr_table_dirty = true; |
| 541 | } |
| 542 | if (self.phdr_load_rw_index == null) { |
| 543 | self.phdr_load_rw_index = @intCast(u16, self.program_headers.items.len); |
| 544 | // TODO Find a hint about how much data need to be in data ? |
| 545 | const file_size = 1024; |
| 546 | // Same reason as for GOT |
| 547 | const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); |
| 548 | const off = self.findFreeSpace(file_size, p_align); |
| 549 | log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 550 | // TODO Same as for GOT |
| 551 | const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x6000000 else 0xc000; |
| 552 | try self.program_headers.append(self.base.allocator, .{ |
| 553 | .p_type = elf.PT_LOAD, |
| 554 | .p_offset = off, |
| 555 | .p_filesz = file_size, |
| 556 | .p_vaddr = rwdata_addr, |
| 557 | .p_paddr = rwdata_addr, |
| 558 | .p_memsz = file_size, |
| 559 | .p_align = p_align, |
| 560 | .p_flags = elf.PF_R | elf.PF_W, |
| 561 | }); |
| 562 | try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{}); |
| 530 | 563 | self.phdr_table_dirty = true; |
| 531 | 564 | } |
| 532 | 565 | if (self.shstrtab_index == null) { |
| ... | ... | @@ -550,8 +583,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 550 | 583 | self.shstrtab_dirty = true; |
| 551 | 584 | self.shdr_table_dirty = true; |
| 552 | 585 | } |
| 553 | | if (self.text_block_list.section_index == null) { |
| 554 | | self.text_block_list.section_index = @intCast(u16, self.sections.items.len); |
| 586 | if (self.text_section_index == null) { |
| 587 | self.text_section_index = @intCast(u16, self.sections.items.len); |
| 555 | 588 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 556 | 589 | |
| 557 | 590 | try self.sections.append(self.base.allocator, .{ |
| ... | ... | @@ -566,6 +599,11 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 566 | 599 | .sh_addralign = phdr.p_align, |
| 567 | 600 | .sh_entsize = 0, |
| 568 | 601 | }); |
| 602 | try self.phdr_shdr_table.putNoClobber( |
| 603 | self.base.allocator, |
| 604 | self.phdr_load_re_index.?, |
| 605 | self.text_section_index.?, |
| 606 | ); |
| 569 | 607 | self.shdr_table_dirty = true; |
| 570 | 608 | } |
| 571 | 609 | if (self.got_section_index == null) { |
| ... | ... | @@ -584,10 +622,15 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 584 | 622 | .sh_addralign = phdr.p_align, |
| 585 | 623 | .sh_entsize = 0, |
| 586 | 624 | }); |
| 625 | try self.phdr_shdr_table.putNoClobber( |
| 626 | self.base.allocator, |
| 627 | self.phdr_got_index.?, |
| 628 | self.got_section_index.?, |
| 629 | ); |
| 587 | 630 | self.shdr_table_dirty = true; |
| 588 | 631 | } |
| 589 | | if (self.rodata_block_list.section_index == null) { |
| 590 | | self.rodata_block_list.section_index = @intCast(u16, self.sections.items.len); |
| 632 | if (self.rodata_section_index == null) { |
| 633 | self.rodata_section_index = @intCast(u16, self.sections.items.len); |
| 591 | 634 | const phdr = &self.program_headers.items[self.phdr_load_ro_index.?]; |
| 592 | 635 | |
| 593 | 636 | try self.sections.append(self.base.allocator, .{ |
| ... | ... | @@ -602,6 +645,34 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 602 | 645 | .sh_addralign = phdr.p_align, |
| 603 | 646 | .sh_entsize = 0, |
| 604 | 647 | }); |
| 648 | try self.phdr_shdr_table.putNoClobber( |
| 649 | self.base.allocator, |
| 650 | self.phdr_load_ro_index.?, |
| 651 | self.rodata_section_index.?, |
| 652 | ); |
| 653 | self.shdr_table_dirty = true; |
| 654 | } |
| 655 | if (self.data_section_index == null) { |
| 656 | self.data_section_index = @intCast(u16, self.sections.items.len); |
| 657 | const phdr = &self.program_headers.items[self.phdr_load_rw_index.?]; |
| 658 | |
| 659 | try self.sections.append(self.base.allocator, .{ |
| 660 | .sh_name = try self.makeString(".data"), |
| 661 | .sh_type = elf.SHT_PROGBITS, |
| 662 | .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC, |
| 663 | .sh_addr = phdr.p_vaddr, |
| 664 | .sh_offset = phdr.p_offset, |
| 665 | .sh_size = phdr.p_filesz, |
| 666 | .sh_link = 0, |
| 667 | .sh_info = 0, |
| 668 | .sh_addralign = phdr.p_align, |
| 669 | .sh_entsize = 0, |
| 670 | }); |
| 671 | try self.phdr_shdr_table.putNoClobber( |
| 672 | self.base.allocator, |
| 673 | self.phdr_load_rw_index.?, |
| 674 | self.data_section_index.?, |
| 675 | ); |
| 605 | 676 | self.shdr_table_dirty = true; |
| 606 | 677 | } |
| 607 | 678 | if (self.symtab_section_index == null) { |
| ... | ... | @@ -2072,17 +2143,18 @@ fn writeElfHeader(self: *Elf) !void { |
| 2072 | 2143 | try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); |
| 2073 | 2144 | } |
| 2074 | 2145 | |
| 2075 | | fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock) void { |
| 2146 | fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void { |
| 2147 | const free_list = self.atom_free_lists.getPtr(phdr_index).?; |
| 2076 | 2148 | var already_have_free_list_node = false; |
| 2077 | 2149 | { |
| 2078 | 2150 | var i: usize = 0; |
| 2079 | | // TODO turn text_block_free_list into a hash map |
| 2080 | | while (i < block_list.free_list.items.len) { |
| 2081 | | if (block_list.free_list.items[i] == text_block) { |
| 2082 | | _ = block_list.free_list.swapRemove(i); |
| 2151 | // TODO turn free_list into a hash map |
| 2152 | while (i < free_list.items.len) { |
| 2153 | if (free_list.items[i] == text_block) { |
| 2154 | _ = free_list.swapRemove(i); |
| 2083 | 2155 | continue; |
| 2084 | 2156 | } |
| 2085 | | if (block_list.free_list.items[i] == text_block.prev) { |
| 2157 | if (free_list.items[i] == text_block.prev) { |
| 2086 | 2158 | already_have_free_list_node = true; |
| 2087 | 2159 | } |
| 2088 | 2160 | i += 1; |
| ... | ... | @@ -2090,10 +2162,17 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock) |
| 2090 | 2162 | } |
| 2091 | 2163 | // TODO process free list for dbg info just like we do above for vaddrs |
| 2092 | 2164 | |
| 2093 | | if (block_list.last_block == text_block) { |
| 2094 | | // TODO shrink the .text section size here |
| 2095 | | block_list.last_block = text_block.prev; |
| 2165 | if (self.atoms.getPtr(phdr_index)) |last_block| { |
| 2166 | if (last_block.* == text_block) { |
| 2167 | if (text_block.prev) |prev| { |
| 2168 | // TODO shrink the section size here |
| 2169 | last_block.* = prev; |
| 2170 | } else { |
| 2171 | _ = self.atoms.fetchRemove(phdr_index); |
| 2172 | } |
| 2173 | } |
| 2096 | 2174 | } |
| 2175 | |
| 2097 | 2176 | if (self.dbg_info_decl_first == text_block) { |
| 2098 | 2177 | self.dbg_info_decl_first = text_block.dbg_info_next; |
| 2099 | 2178 | } |
| ... | ... | @@ -2108,7 +2187,7 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock) |
| 2108 | 2187 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { |
| 2109 | 2188 | // The free list is heuristics, it doesn't have to be perfect, so we can |
| 2110 | 2189 | // ignore the OOM here. |
| 2111 | | block_list.free_list.append(self.base.allocator, prev) catch {}; |
| 2190 | free_list.append(self.base.allocator, prev) catch {}; |
| 2112 | 2191 | } |
| 2113 | 2192 | } else { |
| 2114 | 2193 | text_block.prev = null; |
| ... | ... | @@ -2135,24 +2214,25 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock) |
| 2135 | 2214 | } |
| 2136 | 2215 | } |
| 2137 | 2216 | |
| 2138 | | fn shrinkTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64) void { |
| 2217 | fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr_index: u16) void { |
| 2139 | 2218 | _ = self; |
| 2140 | | _ = block_list; |
| 2141 | 2219 | _ = text_block; |
| 2142 | 2220 | _ = new_block_size; |
| 2221 | _ = phdr_index; |
| 2143 | 2222 | } |
| 2144 | 2223 | |
| 2145 | | fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 2224 | fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 { |
| 2146 | 2225 | const sym = self.local_symbols.items[text_block.local_sym_index]; |
| 2147 | 2226 | const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; |
| 2148 | 2227 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); |
| 2149 | 2228 | if (!need_realloc) return sym.st_value; |
| 2150 | | return self.allocateTextBlock(block_list, text_block, new_block_size, alignment); |
| 2229 | return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index); |
| 2151 | 2230 | } |
| 2152 | 2231 | |
| 2153 | | fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 2154 | | const phdr = &self.program_headers.items[block_list.phdr_index.?]; |
| 2155 | | const shdr = &self.sections.items[block_list.section_index.?]; |
| 2232 | fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 { |
| 2233 | const shdr_index = self.phdr_shdr_table.get(phdr_index).?; |
| 2234 | const phdr = &self.program_headers.items[phdr_index]; |
| 2235 | const shdr = &self.sections.items[shdr_index]; |
| 2156 | 2236 | const new_block_ideal_capacity = padToIdeal(new_block_size); |
| 2157 | 2237 | |
| 2158 | 2238 | // We use these to indicate our intention to update metadata, placing the new block, |
| ... | ... | @@ -2162,13 +2242,14 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2162 | 2242 | // is actually carried out at the end of the function, when errors are no longer possible. |
| 2163 | 2243 | var block_placement: ?*TextBlock = null; |
| 2164 | 2244 | var free_list_removal: ?usize = null; |
| 2245 | var free_list = self.atom_free_lists.get(phdr_index).?; |
| 2165 | 2246 | |
| 2166 | 2247 | // First we look for an appropriately sized free list node. |
| 2167 | 2248 | // The list is unordered. We'll just take the first thing that works. |
| 2168 | 2249 | const vaddr = blk: { |
| 2169 | 2250 | var i: usize = 0; |
| 2170 | | while (i < block_list.free_list.items.len) { |
| 2171 | | const big_block = block_list.free_list.items[i]; |
| 2251 | while (i < free_list.items.len) { |
| 2252 | const big_block = free_list.items[i]; |
| 2172 | 2253 | // We now have a pointer to a live text block that has too much capacity. |
| 2173 | 2254 | // Is it enough that we could fit this new text block? |
| 2174 | 2255 | const sym = self.local_symbols.items[big_block.local_sym_index]; |
| ... | ... | @@ -2183,7 +2264,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2183 | 2264 | // should be deleted because the block that it points to has grown to take up |
| 2184 | 2265 | // more of the extra capacity. |
| 2185 | 2266 | if (!big_block.freeListEligible(self.*)) { |
| 2186 | | _ = block_list.free_list.swapRemove(i); |
| 2267 | _ = free_list.swapRemove(i); |
| 2187 | 2268 | } else { |
| 2188 | 2269 | i += 1; |
| 2189 | 2270 | } |
| ... | ... | @@ -2201,7 +2282,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2201 | 2282 | free_list_removal = i; |
| 2202 | 2283 | } |
| 2203 | 2284 | break :blk new_start_vaddr; |
| 2204 | | } else if (block_list.last_block) |last| { |
| 2285 | } else if (self.atoms.get(phdr_index)) |last| { |
| 2205 | 2286 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2206 | 2287 | const ideal_capacity = padToIdeal(sym.st_size); |
| 2207 | 2288 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; |
| ... | ... | @@ -2221,7 +2302,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2221 | 2302 | if (needed_size > text_capacity) { |
| 2222 | 2303 | // Must move the entire text section. |
| 2223 | 2304 | const new_offset = self.findFreeSpace(needed_size, 0x1000); |
| 2224 | | const text_size = if (block_list.last_block) |last| blk: { |
| 2305 | const text_size = if (self.atoms.get(phdr_index)) |last| blk: { |
| 2225 | 2306 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2226 | 2307 | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; |
| 2227 | 2308 | } else 0; |
| ... | ... | @@ -2230,7 +2311,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2230 | 2311 | shdr.sh_offset = new_offset; |
| 2231 | 2312 | phdr.p_offset = new_offset; |
| 2232 | 2313 | } |
| 2233 | | block_list.last_block = text_block; |
| 2314 | _ = try self.atoms.put(self.base.allocator, phdr_index, text_block); |
| 2234 | 2315 | |
| 2235 | 2316 | shdr.sh_size = needed_size; |
| 2236 | 2317 | phdr.p_memsz = needed_size; |
| ... | ... | @@ -2268,19 +2349,11 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2268 | 2349 | text_block.next = null; |
| 2269 | 2350 | } |
| 2270 | 2351 | if (free_list_removal) |i| { |
| 2271 | | _ = block_list.free_list.swapRemove(i); |
| 2352 | _ = free_list.swapRemove(i); |
| 2272 | 2353 | } |
| 2273 | 2354 | return vaddr; |
| 2274 | 2355 | } |
| 2275 | 2356 | |
| 2276 | | /// Get the block list corresponding to a specific decl |
| 2277 | | /// For example, if the decl is a function, it returns the list of the section .text |
| 2278 | | fn getDeclBlockList(self: *Elf, decl: *const Module.Decl) *TextBlockList { |
| 2279 | | // const is_fn = decl.val.tag() == .function; |
| 2280 | | const is_fn = decl.ty.zigTypeTag() == .Fn; |
| 2281 | | return if (is_fn) &self.text_block_list else &self.rodata_block_list; |
| 2282 | | } |
| 2283 | | |
| 2284 | 2357 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2285 | 2358 | if (self.llvm_object) |_| return; |
| 2286 | 2359 | |
| ... | ... | @@ -2288,6 +2361,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2288 | 2361 | |
| 2289 | 2362 | try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1); |
| 2290 | 2363 | try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1); |
| 2364 | try self.decls.putNoClobber(self.base.allocator, decl, null); |
| 2291 | 2365 | |
| 2292 | 2366 | if (self.local_symbol_free_list.popOrNull()) |i| { |
| 2293 | 2367 | log.debug("reusing symbol index {d} for {s}", .{ i, decl.name }); |
| ... | ... | @@ -2306,14 +2380,12 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2306 | 2380 | self.offset_table_count_dirty = true; |
| 2307 | 2381 | } |
| 2308 | 2382 | |
| 2309 | | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 2310 | | |
| 2311 | 2383 | self.local_symbols.items[decl.link.elf.local_sym_index] = .{ |
| 2312 | 2384 | .st_name = 0, |
| 2313 | 2385 | .st_info = 0, |
| 2314 | 2386 | .st_other = 0, |
| 2315 | 2387 | .st_shndx = 0, |
| 2316 | | .st_value = phdr.p_vaddr, |
| 2388 | .st_value = 0, |
| 2317 | 2389 | .st_size = 0, |
| 2318 | 2390 | }; |
| 2319 | 2391 | self.offset_table.items[decl.link.elf.offset_table_index] = 0; |
| ... | ... | @@ -2324,10 +2396,12 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2324 | 2396 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); |
| 2325 | 2397 | } |
| 2326 | 2398 | |
| 2327 | | const block_list = self.getDeclBlockList(decl); |
| 2399 | const kv = self.decls.fetchRemove(decl); |
| 2400 | if (kv.?.value) |index| { |
| 2401 | self.freeTextBlock(&decl.link.elf, index); |
| 2402 | } |
| 2328 | 2403 | |
| 2329 | 2404 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 2330 | | self.freeTextBlock(block_list, &decl.link.elf); |
| 2331 | 2405 | if (decl.link.elf.local_sym_index != 0) { |
| 2332 | 2406 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; |
| 2333 | 2407 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; |
| ... | ... | @@ -2366,11 +2440,39 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void { |
| 2366 | 2440 | table.deinit(gpa); |
| 2367 | 2441 | } |
| 2368 | 2442 | |
| 2443 | fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 { |
| 2444 | const ty = decl.ty; |
| 2445 | const zig_ty = ty.zigTypeTag(); |
| 2446 | const val = decl.val; |
| 2447 | const phdr_index: u16 = blk: { |
| 2448 | if (val.isUndefDeep()) { |
| 2449 | // TODO in release-fast and release-small, we should put undef in .bss |
| 2450 | break :blk self.phdr_load_rw_index.?; |
| 2451 | } |
| 2452 | |
| 2453 | switch (zig_ty) { |
| 2454 | .Fn => break :blk self.phdr_load_re_index.?, |
| 2455 | else => { |
| 2456 | if (val.castTag(.variable)) |_| { |
| 2457 | break :blk self.phdr_load_rw_index.?; |
| 2458 | } |
| 2459 | break :blk self.phdr_load_ro_index.?; |
| 2460 | }, |
| 2461 | } |
| 2462 | }; |
| 2463 | return phdr_index; |
| 2464 | } |
| 2465 | |
| 2369 | 2466 | fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym { |
| 2370 | 2467 | log.debug("updateDeclCode {s}{*}", .{ mem.sliceTo(decl.name, 0), decl }); |
| 2371 | 2468 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 2372 | 2469 | |
| 2373 | | const block_list = self.getDeclBlockList(decl); |
| 2470 | const decl_ptr = self.decls.getPtr(decl).?; |
| 2471 | if (decl_ptr.* == null) { |
| 2472 | decl_ptr.* = try self.getDeclPhdrIndex(decl); |
| 2473 | } |
| 2474 | const phdr_index = decl_ptr.*.?; |
| 2475 | const shdr_index = self.phdr_shdr_table.get(phdr_index).?; |
| 2374 | 2476 | |
| 2375 | 2477 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 2376 | 2478 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; |
| ... | ... | @@ -2379,7 +2481,7 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2379 | 2481 | const need_realloc = code.len > capacity or |
| 2380 | 2482 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); |
| 2381 | 2483 | if (need_realloc) { |
| 2382 | | const vaddr = try self.growTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |
| 2484 | const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index); |
| 2383 | 2485 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr }); |
| 2384 | 2486 | if (vaddr != local_sym.st_value) { |
| 2385 | 2487 | local_sym.st_value = vaddr; |
| ... | ... | @@ -2389,28 +2491,28 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2389 | 2491 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); |
| 2390 | 2492 | } |
| 2391 | 2493 | } else if (code.len < local_sym.st_size) { |
| 2392 | | self.shrinkTextBlock(block_list, &decl.link.elf, code.len); |
| 2494 | self.shrinkTextBlock(&decl.link.elf, code.len, phdr_index); |
| 2393 | 2495 | } |
| 2394 | 2496 | local_sym.st_size = code.len; |
| 2395 | 2497 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0)); |
| 2396 | 2498 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; |
| 2397 | 2499 | local_sym.st_other = 0; |
| 2398 | | local_sym.st_shndx = block_list.section_index.?; |
| 2500 | local_sym.st_shndx = shdr_index; |
| 2399 | 2501 | // TODO this write could be avoided if no fields of the symbol were changed. |
| 2400 | 2502 | try self.writeSymbol(decl.link.elf.local_sym_index); |
| 2401 | 2503 | } else { |
| 2402 | 2504 | const decl_name = mem.sliceTo(decl.name, 0); |
| 2403 | 2505 | const name_str_index = try self.makeString(decl_name); |
| 2404 | | const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |
| 2405 | | errdefer self.freeTextBlock(block_list, &decl.link.elf); |
| 2506 | const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index); |
| 2507 | errdefer self.freeTextBlock(&decl.link.elf, phdr_index); |
| 2406 | 2508 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); |
| 2407 | | errdefer self.freeTextBlock(block_list, &decl.link.elf); |
| 2509 | errdefer self.freeTextBlock(&decl.link.elf, phdr_index); |
| 2408 | 2510 | |
| 2409 | 2511 | local_sym.* = .{ |
| 2410 | 2512 | .st_name = name_str_index, |
| 2411 | 2513 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, |
| 2412 | 2514 | .st_other = 0, |
| 2413 | | .st_shndx = block_list.section_index.?, |
| 2515 | .st_shndx = shdr_index, |
| 2414 | 2516 | .st_value = vaddr, |
| 2415 | 2517 | .st_size = code.len, |
| 2416 | 2518 | }; |
| ... | ... | @@ -2420,8 +2522,8 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2420 | 2522 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); |
| 2421 | 2523 | } |
| 2422 | 2524 | |
| 2423 | | const section_offset = local_sym.st_value - self.program_headers.items[block_list.phdr_index.?].p_vaddr; |
| 2424 | | const file_offset = self.sections.items[block_list.section_index.?].sh_offset + section_offset; |
| 2525 | const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr; |
| 2526 | const file_offset = self.sections.items[shdr_index].sh_offset + section_offset; |
| 2425 | 2527 | try self.base.file.?.pwriteAll(code, file_offset); |
| 2426 | 2528 | |
| 2427 | 2529 | return local_sym; |
| ... | ... | @@ -3008,7 +3110,12 @@ pub fn updateDeclExports( |
| 3008 | 3110 | if (decl.link.elf.local_sym_index == 0) return; |
| 3009 | 3111 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 3010 | 3112 | |
| 3011 | | const block_list = self.getDeclBlockList(decl); |
| 3113 | const decl_ptr = self.decls.getPtr(decl).?; |
| 3114 | if (decl_ptr.* == null) { |
| 3115 | decl_ptr.* = try self.getDeclPhdrIndex(decl); |
| 3116 | } |
| 3117 | const phdr_index = decl_ptr.*.?; |
| 3118 | const shdr_index = self.phdr_shdr_table.get(phdr_index).?; |
| 3012 | 3119 | |
| 3013 | 3120 | for (exports) |exp| { |
| 3014 | 3121 | if (exp.options.section) |section_name| { |
| ... | ... | @@ -3047,7 +3154,7 @@ pub fn updateDeclExports( |
| 3047 | 3154 | .st_name = try self.updateString(sym.st_name, exp.options.name), |
| 3048 | 3155 | .st_info = (stb_bits << 4) | stt_bits, |
| 3049 | 3156 | .st_other = 0, |
| 3050 | | .st_shndx = block_list.section_index.?, |
| 3157 | .st_shndx = shdr_index, |
| 3051 | 3158 | .st_value = decl_sym.st_value, |
| 3052 | 3159 | .st_size = decl_sym.st_size, |
| 3053 | 3160 | }; |
| ... | ... | @@ -3061,7 +3168,7 @@ pub fn updateDeclExports( |
| 3061 | 3168 | .st_name = name, |
| 3062 | 3169 | .st_info = (stb_bits << 4) | stt_bits, |
| 3063 | 3170 | .st_other = 0, |
| 3064 | | .st_shndx = block_list.section_index.?, |
| 3171 | .st_shndx = shdr_index, |
| 3065 | 3172 | .st_value = decl_sym.st_value, |
| 3066 | 3173 | .st_size = decl_sym.st_size, |
| 3067 | 3174 | }; |