| ... | @@ -54,13 +54,14 @@ phdr_load_re_index: ?u16 = null, | ... | @@ -54,13 +54,14 @@ phdr_load_re_index: ?u16 = null, |
| 54 | /// The index into the program headers of the global offset table. | 54 | /// The index into the program headers of the global offset table. |
| 55 | /// It needs PT_LOAD and Read flags. | 55 | /// It needs PT_LOAD and Read flags. |
| 56 | phdr_got_index: ?u16 = null, | 56 | phdr_got_index: ?u16 = null, |
| | 57 | /// The index into the program headers of a PT_LOAD program header with Read flag |
| | 58 | phdr_load_ro_index: ?u16 = null, |
| 57 | entry_addr: ?u64 = null, | 59 | entry_addr: ?u64 = null, |
| 58 | | 60 | |
| 59 | debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, | 61 | debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, |
| 60 | shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, | 62 | shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, |
| 61 | shstrtab_index: ?u16 = null, | 63 | shstrtab_index: ?u16 = null, |
| 62 | | 64 | |
| 63 | text_section_index: ?u16 = null, | | |
| 64 | symtab_section_index: ?u16 = null, | 65 | symtab_section_index: ?u16 = null, |
| 65 | got_section_index: ?u16 = null, | 66 | got_section_index: ?u16 = null, |
| 66 | debug_info_section_index: ?u16 = null, | 67 | debug_info_section_index: ?u16 = null, |
| ... | @@ -115,8 +116,8 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -115,8 +116,8 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 115 | /// overcapacity can be negative. A simple way to have negative overcapacity is to | 116 | /// overcapacity can be negative. A simple way to have negative overcapacity is to |
| 116 | /// allocate a fresh text block, which will have ideal capacity, and then grow it | 117 | /// allocate a fresh text block, which will have ideal capacity, and then grow it |
| 117 | /// by 1 byte. It will then have -1 overcapacity. | 118 | /// by 1 byte. It will then have -1 overcapacity. |
| 118 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | 119 | text_block_list: TextBlockList = .{}, |
| 119 | last_text_block: ?*TextBlock = null, | 120 | rodata_block_list: TextBlockList = .{}, |
| 120 | | 121 | |
| 121 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. | 122 | /// A list of `SrcFn` whose Line Number Programs have surplus capacity. |
| 122 | /// This is the same concept as `text_block_free_list`; see those doc comments. | 123 | /// This is the same concept as `text_block_free_list`; see those doc comments. |
| ... | @@ -204,6 +205,14 @@ pub const TextBlock = struct { | ... | @@ -204,6 +205,14 @@ pub const TextBlock = struct { |
| 204 | } | 205 | } |
| 205 | }; | 206 | }; |
| 206 | | 207 | |
| | 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 | |
| 207 | pub const Export = struct { | 216 | pub const Export = struct { |
| 208 | sym_index: ?u32 = null, | 217 | sym_index: ?u32 = null, |
| 209 | }; | 218 | }; |
| ... | @@ -314,7 +323,8 @@ pub fn deinit(self: *Elf) void { | ... | @@ -314,7 +323,8 @@ pub fn deinit(self: *Elf) void { |
| 314 | self.global_symbol_free_list.deinit(self.base.allocator); | 323 | self.global_symbol_free_list.deinit(self.base.allocator); |
| 315 | self.local_symbol_free_list.deinit(self.base.allocator); | 324 | self.local_symbol_free_list.deinit(self.base.allocator); |
| 316 | self.offset_table_free_list.deinit(self.base.allocator); | 325 | self.offset_table_free_list.deinit(self.base.allocator); |
| 317 | self.text_block_free_list.deinit(self.base.allocator); | 326 | self.text_block_list.free_list.deinit(self.base.allocator); |
| | 327 | self.rodata_block_list.free_list.deinit(self.base.allocator); |
| 318 | self.dbg_line_fn_free_list.deinit(self.base.allocator); | 328 | self.dbg_line_fn_free_list.deinit(self.base.allocator); |
| 319 | self.dbg_info_decl_free_list.deinit(self.base.allocator); | 329 | self.dbg_info_decl_free_list.deinit(self.base.allocator); |
| 320 | self.offset_table.deinit(self.base.allocator); | 330 | self.offset_table.deinit(self.base.allocator); |
| ... | @@ -450,6 +460,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -450,6 +460,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 450 | const ptr_size: u8 = self.ptrWidthBytes(); | 460 | const ptr_size: u8 = self.ptrWidthBytes(); |
| 451 | if (self.phdr_load_re_index == null) { | 461 | if (self.phdr_load_re_index == null) { |
| 452 | self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); | 462 | self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len); |
| | 463 | self.text_block_list.phdr_index = self.phdr_load_re_index; |
| 453 | const file_size = self.base.options.program_code_size_hint; | 464 | const file_size = self.base.options.program_code_size_hint; |
| 454 | const p_align = 0x1000; | 465 | const p_align = 0x1000; |
| 455 | const off = self.findFreeSpace(file_size, p_align); | 466 | const off = self.findFreeSpace(file_size, p_align); |
| ... | @@ -492,6 +503,29 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -492,6 +503,29 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 492 | }); | 503 | }); |
| 493 | self.phdr_table_dirty = true; | 504 | self.phdr_table_dirty = true; |
| 494 | } | 505 | } |
| | 506 | if (self.phdr_load_ro_index == null) { |
| | 507 | self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len); |
| | 508 | self.rodata_block_list.phdr_index = self.phdr_load_ro_index; |
| | 509 | // TODO Find a hint about how much data need to be in rodata ? |
| | 510 | const file_size = 1024; |
| | 511 | // Same reason as for GOT |
| | 512 | const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size); |
| | 513 | const off = self.findFreeSpace(file_size, p_align); |
| | 514 | log.debug("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| | 515 | // TODO Same as for GOT |
| | 516 | const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x6000000 else 0xD000; |
| | 517 | try self.program_headers.append(self.base.allocator, .{ |
| | 518 | .p_type = elf.PT_LOAD, |
| | 519 | .p_offset = off, |
| | 520 | .p_filesz = file_size, |
| | 521 | .p_vaddr = rodata_addr, |
| | 522 | .p_paddr = rodata_addr, |
| | 523 | .p_memsz = file_size, |
| | 524 | .p_align = p_align, |
| | 525 | .p_flags = elf.PF_R, |
| | 526 | }); |
| | 527 | self.phdr_table_dirty = true; |
| | 528 | } |
| 495 | if (self.shstrtab_index == null) { | 529 | if (self.shstrtab_index == null) { |
| 496 | self.shstrtab_index = @intCast(u16, self.sections.items.len); | 530 | self.shstrtab_index = @intCast(u16, self.sections.items.len); |
| 497 | assert(self.shstrtab.items.len == 0); | 531 | assert(self.shstrtab.items.len == 0); |
| ... | @@ -513,8 +547,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -513,8 +547,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 513 | self.shstrtab_dirty = true; | 547 | self.shstrtab_dirty = true; |
| 514 | self.shdr_table_dirty = true; | 548 | self.shdr_table_dirty = true; |
| 515 | } | 549 | } |
| 516 | if (self.text_section_index == null) { | 550 | if (self.text_block_list.section_index == null) { |
| 517 | self.text_section_index = @intCast(u16, self.sections.items.len); | 551 | self.text_block_list.section_index = @intCast(u16, self.sections.items.len); |
| 518 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | 552 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 519 | | 553 | |
| 520 | try self.sections.append(self.base.allocator, .{ | 554 | try self.sections.append(self.base.allocator, .{ |
| ... | @@ -549,6 +583,24 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -549,6 +583,24 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 549 | }); | 583 | }); |
| 550 | self.shdr_table_dirty = true; | 584 | self.shdr_table_dirty = true; |
| 551 | } | 585 | } |
| | 586 | if (self.rodata_block_list.section_index == null) { |
| | 587 | self.rodata_block_list.section_index = @intCast(u16, self.sections.items.len); |
| | 588 | const phdr = &self.program_headers.items[self.phdr_load_ro_index.?]; |
| | 589 | |
| | 590 | try self.sections.append(self.base.allocator, .{ |
| | 591 | .sh_name = try self.makeString(".rodata"), |
| | 592 | .sh_type = elf.SHT_PROGBITS, |
| | 593 | .sh_flags = elf.SHF_ALLOC, |
| | 594 | .sh_addr = phdr.p_vaddr, |
| | 595 | .sh_offset = phdr.p_offset, |
| | 596 | .sh_size = phdr.p_filesz, |
| | 597 | .sh_link = 0, |
| | 598 | .sh_info = 0, |
| | 599 | .sh_addralign = phdr.p_align, |
| | 600 | .sh_entsize = 0, |
| | 601 | }); |
| | 602 | self.shdr_table_dirty = true; |
| | 603 | } |
| 552 | if (self.symtab_section_index == null) { | 604 | if (self.symtab_section_index == null) { |
| 553 | self.symtab_section_index = @intCast(u16, self.sections.items.len); | 605 | self.symtab_section_index = @intCast(u16, self.sections.items.len); |
| 554 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | 606 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
| ... | @@ -1927,17 +1979,17 @@ fn writeElfHeader(self: *Elf) !void { | ... | @@ -1927,17 +1979,17 @@ fn writeElfHeader(self: *Elf) !void { |
| 1927 | try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); | 1979 | try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); |
| 1928 | } | 1980 | } |
| 1929 | | 1981 | |
| 1930 | fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { | 1982 | fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock) void { |
| 1931 | var already_have_free_list_node = false; | 1983 | var already_have_free_list_node = false; |
| 1932 | { | 1984 | { |
| 1933 | var i: usize = 0; | 1985 | var i: usize = 0; |
| 1934 | // TODO turn text_block_free_list into a hash map | 1986 | // TODO turn text_block_free_list into a hash map |
| 1935 | while (i < self.text_block_free_list.items.len) { | 1987 | while (i < block_list.free_list.items.len) { |
| 1936 | if (self.text_block_free_list.items[i] == text_block) { | 1988 | if (block_list.free_list.items[i] == text_block) { |
| 1937 | _ = self.text_block_free_list.swapRemove(i); | 1989 | _ = block_list.free_list.swapRemove(i); |
| 1938 | continue; | 1990 | continue; |
| 1939 | } | 1991 | } |
| 1940 | if (self.text_block_free_list.items[i] == text_block.prev) { | 1992 | if (block_list.free_list.items[i] == text_block.prev) { |
| 1941 | already_have_free_list_node = true; | 1993 | already_have_free_list_node = true; |
| 1942 | } | 1994 | } |
| 1943 | i += 1; | 1995 | i += 1; |
| ... | @@ -1945,9 +1997,9 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { | ... | @@ -1945,9 +1997,9 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { |
| 1945 | } | 1997 | } |
| 1946 | // TODO process free list for dbg info just like we do above for vaddrs | 1998 | // TODO process free list for dbg info just like we do above for vaddrs |
| 1947 | | 1999 | |
| 1948 | if (self.last_text_block == text_block) { | 2000 | if (block_list.last_block == text_block) { |
| 1949 | // TODO shrink the .text section size here | 2001 | // TODO shrink the .text section size here |
| 1950 | self.last_text_block = text_block.prev; | 2002 | block_list.last_block = text_block.prev; |
| 1951 | } | 2003 | } |
| 1952 | if (self.dbg_info_decl_first == text_block) { | 2004 | if (self.dbg_info_decl_first == text_block) { |
| 1953 | self.dbg_info_decl_first = text_block.dbg_info_next; | 2005 | self.dbg_info_decl_first = text_block.dbg_info_next; |
| ... | @@ -1963,7 +2015,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { | ... | @@ -1963,7 +2015,7 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { |
| 1963 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { | 2015 | if (!already_have_free_list_node and prev.freeListEligible(self.*)) { |
| 1964 | // The free list is heuristics, it doesn't have to be perfect, so we can | 2016 | // The free list is heuristics, it doesn't have to be perfect, so we can |
| 1965 | // ignore the OOM here. | 2017 | // ignore the OOM here. |
| 1966 | self.text_block_free_list.append(self.base.allocator, prev) catch {}; | 2018 | block_list.free_list.append(self.base.allocator, prev) catch {}; |
| 1967 | } | 2019 | } |
| 1968 | } else { | 2020 | } else { |
| 1969 | text_block.prev = null; | 2021 | text_block.prev = null; |
| ... | @@ -1990,25 +2042,24 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { | ... | @@ -1990,25 +2042,24 @@ fn freeTextBlock(self: *Elf, text_block: *TextBlock) void { |
| 1990 | } | 2042 | } |
| 1991 | } | 2043 | } |
| 1992 | | 2044 | |
| 1993 | fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64) void { | 2045 | fn shrinkTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64) void { |
| 1994 | _ = self; | 2046 | _ = self; |
| | 2047 | _ = block_list; |
| 1995 | _ = text_block; | 2048 | _ = text_block; |
| 1996 | _ = new_block_size; | 2049 | _ = new_block_size; |
| 1997 | // TODO check the new capacity, and if it crosses the size threshold into a big enough | | |
| 1998 | // capacity, insert a free list node for it. | | |
| 1999 | } | 2050 | } |
| 2000 | | 2051 | |
| 2001 | fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 2052 | fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 2002 | const sym = self.local_symbols.items[text_block.local_sym_index]; | 2053 | const sym = self.local_symbols.items[text_block.local_sym_index]; |
| 2003 | const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; | 2054 | const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value; |
| 2004 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); | 2055 | const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*); |
| 2005 | if (!need_realloc) return sym.st_value; | 2056 | if (!need_realloc) return sym.st_value; |
| 2006 | return self.allocateTextBlock(text_block, new_block_size, alignment); | 2057 | return self.allocateTextBlock(block_list, text_block, new_block_size, alignment); |
| 2007 | } | 2058 | } |
| 2008 | | 2059 | |
| 2009 | fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 2060 | fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 2010 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; | 2061 | const phdr = &self.program_headers.items[block_list.phdr_index.?]; |
| 2011 | const shdr = &self.sections.items[self.text_section_index.?]; | 2062 | const shdr = &self.sections.items[block_list.section_index.?]; |
| 2012 | const new_block_ideal_capacity = padToIdeal(new_block_size); | 2063 | const new_block_ideal_capacity = padToIdeal(new_block_size); |
| 2013 | | 2064 | |
| 2014 | // We use these to indicate our intention to update metadata, placing the new block, | 2065 | // We use these to indicate our intention to update metadata, placing the new block, |
| ... | @@ -2023,8 +2074,8 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2023,8 +2074,8 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2023 | // The list is unordered. We'll just take the first thing that works. | 2074 | // The list is unordered. We'll just take the first thing that works. |
| 2024 | const vaddr = blk: { | 2075 | const vaddr = blk: { |
| 2025 | var i: usize = 0; | 2076 | var i: usize = 0; |
| 2026 | while (i < self.text_block_free_list.items.len) { | 2077 | while (i < block_list.free_list.items.len) { |
| 2027 | const big_block = self.text_block_free_list.items[i]; | 2078 | const big_block = block_list.free_list.items[i]; |
| 2028 | // We now have a pointer to a live text block that has too much capacity. | 2079 | // We now have a pointer to a live text block that has too much capacity. |
| 2029 | // Is it enough that we could fit this new text block? | 2080 | // Is it enough that we could fit this new text block? |
| 2030 | const sym = self.local_symbols.items[big_block.local_sym_index]; | 2081 | const sym = self.local_symbols.items[big_block.local_sym_index]; |
| ... | @@ -2039,7 +2090,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2039,7 +2090,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2039 | // should be deleted because the block that it points to has grown to take up | 2090 | // should be deleted because the block that it points to has grown to take up |
| 2040 | // more of the extra capacity. | 2091 | // more of the extra capacity. |
| 2041 | if (!big_block.freeListEligible(self.*)) { | 2092 | if (!big_block.freeListEligible(self.*)) { |
| 2042 | _ = self.text_block_free_list.swapRemove(i); | 2093 | _ = block_list.free_list.swapRemove(i); |
| 2043 | } else { | 2094 | } else { |
| 2044 | i += 1; | 2095 | i += 1; |
| 2045 | } | 2096 | } |
| ... | @@ -2057,7 +2108,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2057,7 +2108,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2057 | free_list_removal = i; | 2108 | free_list_removal = i; |
| 2058 | } | 2109 | } |
| 2059 | break :blk new_start_vaddr; | 2110 | break :blk new_start_vaddr; |
| 2060 | } else if (self.last_text_block) |last| { | 2111 | } else if (block_list.last_block) |last| { |
| 2061 | const sym = self.local_symbols.items[last.local_sym_index]; | 2112 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2062 | const ideal_capacity = padToIdeal(sym.st_size); | 2113 | const ideal_capacity = padToIdeal(sym.st_size); |
| 2063 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | 2114 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; |
| ... | @@ -2077,7 +2128,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2077,7 +2128,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2077 | if (needed_size > text_capacity) { | 2128 | if (needed_size > text_capacity) { |
| 2078 | // Must move the entire text section. | 2129 | // Must move the entire text section. |
| 2079 | const new_offset = self.findFreeSpace(needed_size, 0x1000); | 2130 | const new_offset = self.findFreeSpace(needed_size, 0x1000); |
| 2080 | const text_size = if (self.last_text_block) |last| blk: { | 2131 | const text_size = if (block_list.last_block) |last| blk: { |
| 2081 | const sym = self.local_symbols.items[last.local_sym_index]; | 2132 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2082 | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; | 2133 | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; |
| 2083 | } else 0; | 2134 | } else 0; |
| ... | @@ -2086,7 +2137,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2086,7 +2137,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2086 | shdr.sh_offset = new_offset; | 2137 | shdr.sh_offset = new_offset; |
| 2087 | phdr.p_offset = new_offset; | 2138 | phdr.p_offset = new_offset; |
| 2088 | } | 2139 | } |
| 2089 | self.last_text_block = text_block; | 2140 | block_list.last_block = text_block; |
| 2090 | | 2141 | |
| 2091 | shdr.sh_size = needed_size; | 2142 | shdr.sh_size = needed_size; |
| 2092 | phdr.p_memsz = needed_size; | 2143 | phdr.p_memsz = needed_size; |
| ... | @@ -2124,11 +2175,19 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al | ... | @@ -2124,11 +2175,19 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2124 | text_block.next = null; | 2175 | text_block.next = null; |
| 2125 | } | 2176 | } |
| 2126 | if (free_list_removal) |i| { | 2177 | if (free_list_removal) |i| { |
| 2127 | _ = self.text_block_free_list.swapRemove(i); | 2178 | _ = block_list.free_list.swapRemove(i); |
| 2128 | } | 2179 | } |
| 2129 | return vaddr; | 2180 | return vaddr; |
| 2130 | } | 2181 | } |
| 2131 | | 2182 | |
| | 2183 | /// Get the block list corresponding to a specific decl |
| | 2184 | /// For example, if the decl is a function, it returns the list of the section .text |
| | 2185 | fn getDeclBlockList(self: *Elf, decl: *const Module.Decl) *TextBlockList { |
| | 2186 | // const is_fn = decl.val.tag() == .function; |
| | 2187 | const is_fn = decl.ty.zigTypeTag() == .Fn; |
| | 2188 | return if (is_fn) &self.text_block_list else &self.rodata_block_list; |
| | 2189 | } |
| | 2190 | |
| 2132 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { | 2191 | pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2133 | if (self.llvm_object) |_| return; | 2192 | if (self.llvm_object) |_| return; |
| 2134 | | 2193 | |
| ... | @@ -2172,8 +2231,10 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | ... | @@ -2172,8 +2231,10 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2172 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); | 2231 | if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl); |
| 2173 | } | 2232 | } |
| 2174 | | 2233 | |
| | 2234 | const block_list = self.getDeclBlockList(decl); |
| | 2235 | |
| 2175 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 2236 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 2176 | self.freeTextBlock(&decl.link.elf); | 2237 | self.freeTextBlock(block_list, &decl.link.elf); |
| 2177 | if (decl.link.elf.local_sym_index != 0) { | 2238 | if (decl.link.elf.local_sym_index != 0) { |
| 2178 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; | 2239 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; |
| 2179 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; | 2240 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; |
| ... | @@ -2216,6 +2277,8 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void { | ... | @@ -2216,6 +2277,8 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void { |
| 2216 | fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym { | 2277 | fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym { |
| 2217 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); | 2278 | const required_alignment = decl.ty.abiAlignment(self.base.options.target); |
| 2218 | | 2279 | |
| | 2280 | const block_list = self.getDeclBlockList(decl); |
| | 2281 | |
| 2219 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() | 2282 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 2220 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; | 2283 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 2221 | if (local_sym.st_size != 0) { | 2284 | if (local_sym.st_size != 0) { |
| ... | @@ -2223,7 +2286,7 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 | ... | @@ -2223,7 +2286,7 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2223 | const need_realloc = code.len > capacity or | 2286 | const need_realloc = code.len > capacity or |
| 2224 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); | 2287 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); |
| 2225 | if (need_realloc) { | 2288 | if (need_realloc) { |
| 2226 | const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment); | 2289 | const vaddr = try self.growTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |
| 2227 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr }); | 2290 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr }); |
| 2228 | if (vaddr != local_sym.st_value) { | 2291 | if (vaddr != local_sym.st_value) { |
| 2229 | local_sym.st_value = vaddr; | 2292 | local_sym.st_value = vaddr; |
| ... | @@ -2233,27 +2296,28 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 | ... | @@ -2233,27 +2296,28 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2233 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | 2296 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); |
| 2234 | } | 2297 | } |
| 2235 | } else if (code.len < local_sym.st_size) { | 2298 | } else if (code.len < local_sym.st_size) { |
| 2236 | self.shrinkTextBlock(&decl.link.elf, code.len); | 2299 | self.shrinkTextBlock(block_list, &decl.link.elf, code.len); |
| 2237 | } | 2300 | } |
| 2238 | local_sym.st_size = code.len; | 2301 | local_sym.st_size = code.len; |
| 2239 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0)); | 2302 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0)); |
| 2240 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; | 2303 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; |
| 2241 | local_sym.st_other = 0; | 2304 | local_sym.st_other = 0; |
| 2242 | local_sym.st_shndx = self.text_section_index.?; | 2305 | local_sym.st_shndx = block_list.section_index.?; |
| 2243 | // TODO this write could be avoided if no fields of the symbol were changed. | 2306 | // TODO this write could be avoided if no fields of the symbol were changed. |
| 2244 | try self.writeSymbol(decl.link.elf.local_sym_index); | 2307 | try self.writeSymbol(decl.link.elf.local_sym_index); |
| 2245 | } else { | 2308 | } else { |
| 2246 | const decl_name = mem.sliceTo(decl.name, 0); | 2309 | const decl_name = mem.sliceTo(decl.name, 0); |
| 2247 | const name_str_index = try self.makeString(decl_name); | 2310 | const name_str_index = try self.makeString(decl_name); |
| 2248 | const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment); | 2311 | const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |
| | 2312 | errdefer self.freeTextBlock(block_list, &decl.link.elf); |
| 2249 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); | 2313 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); |
| 2250 | errdefer self.freeTextBlock(&decl.link.elf); | 2314 | errdefer self.freeTextBlock(block_list, &decl.link.elf); |
| 2251 | | 2315 | |
| 2252 | local_sym.* = .{ | 2316 | local_sym.* = .{ |
| 2253 | .st_name = name_str_index, | 2317 | .st_name = name_str_index, |
| 2254 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, | 2318 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, |
| 2255 | .st_other = 0, | 2319 | .st_other = 0, |
| 2256 | .st_shndx = self.text_section_index.?, | 2320 | .st_shndx = block_list.section_index.?, |
| 2257 | .st_value = vaddr, | 2321 | .st_value = vaddr, |
| 2258 | .st_size = code.len, | 2322 | .st_size = code.len, |
| 2259 | }; | 2323 | }; |
| ... | @@ -2263,8 +2327,8 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 | ... | @@ -2263,8 +2327,8 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2263 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | 2327 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); |
| 2264 | } | 2328 | } |
| 2265 | | 2329 | |
| 2266 | const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr; | 2330 | const section_offset = local_sym.st_value - self.program_headers.items[block_list.phdr_index.?].p_vaddr; |
| 2267 | const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset; | 2331 | const file_offset = self.sections.items[block_list.section_index.?].sh_offset + section_offset; |
| 2268 | try self.base.file.?.pwriteAll(code, file_offset); | 2332 | try self.base.file.?.pwriteAll(code, file_offset); |
| 2269 | | 2333 | |
| 2270 | return local_sym; | 2334 | return local_sym; |
| ... | @@ -2772,6 +2836,8 @@ pub fn updateDeclExports( | ... | @@ -2772,6 +2836,8 @@ pub fn updateDeclExports( |
| 2772 | if (decl.link.elf.local_sym_index == 0) return; | 2836 | if (decl.link.elf.local_sym_index == 0) return; |
| 2773 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; | 2837 | const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 2774 | | 2838 | |
| | 2839 | const block_list = self.getDeclBlockList(decl); |
| | 2840 | |
| 2775 | for (exports) |exp| { | 2841 | for (exports) |exp| { |
| 2776 | if (exp.options.section) |section_name| { | 2842 | if (exp.options.section) |section_name| { |
| 2777 | if (!mem.eql(u8, section_name, ".text")) { | 2843 | if (!mem.eql(u8, section_name, ".text")) { |
| ... | @@ -2808,7 +2874,7 @@ pub fn updateDeclExports( | ... | @@ -2808,7 +2874,7 @@ pub fn updateDeclExports( |
| 2808 | .st_name = try self.updateString(sym.st_name, exp.options.name), | 2874 | .st_name = try self.updateString(sym.st_name, exp.options.name), |
| 2809 | .st_info = (stb_bits << 4) | stt_bits, | 2875 | .st_info = (stb_bits << 4) | stt_bits, |
| 2810 | .st_other = 0, | 2876 | .st_other = 0, |
| 2811 | .st_shndx = self.text_section_index.?, | 2877 | .st_shndx = block_list.section_index.?, |
| 2812 | .st_value = decl_sym.st_value, | 2878 | .st_value = decl_sym.st_value, |
| 2813 | .st_size = decl_sym.st_size, | 2879 | .st_size = decl_sym.st_size, |
| 2814 | }; | 2880 | }; |
| ... | @@ -2822,7 +2888,7 @@ pub fn updateDeclExports( | ... | @@ -2822,7 +2888,7 @@ pub fn updateDeclExports( |
| 2822 | .st_name = name, | 2888 | .st_name = name, |
| 2823 | .st_info = (stb_bits << 4) | stt_bits, | 2889 | .st_info = (stb_bits << 4) | stt_bits, |
| 2824 | .st_other = 0, | 2890 | .st_other = 0, |
| 2825 | .st_shndx = self.text_section_index.?, | 2891 | .st_shndx = block_list.section_index.?, |
| 2826 | .st_value = decl_sym.st_value, | 2892 | .st_value = decl_sym.st_value, |
| 2827 | .st_size = decl_sym.st_size, | 2893 | .st_size = decl_sym.st_size, |
| 2828 | }; | 2894 | }; |