authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-03 00:28:56+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-03 08:47:06+01:00
logb77757fe393dd8cdea1a2bd63a13939ec9beb706
treee0d0f9d5ab1b307c4370fda9efabe90f347fe062
parent557a097523a8c30c25579db3c634c09c9979d3a2

elf: add basic handling of .data section


3 files changed, 186 insertions(+), 75 deletions(-)

src/link/Elf.zig+179-72
...@@ -56,6 +56,11 @@ phdr_load_re_index: ?u16 = null,...@@ -56,6 +56,11 @@ phdr_load_re_index: ?u16 = null,
56phdr_got_index: ?u16 = null,56phdr_got_index: ?u16 = null,
57/// The index into the program headers of a PT_LOAD program header with Read flag57/// The index into the program headers of a PT_LOAD program header with Read flag
58phdr_load_ro_index: ?u16 = null,58phdr_load_ro_index: ?u16 = null,
59/// The index into the program headers of a PT_LOAD program header with Write flag
60phdr_load_rw_index: ?u16 = null,
61
62phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
63
59entry_addr: ?u64 = null,64entry_addr: ?u64 = null,
6065
61debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},66debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
...@@ -63,7 +68,10 @@ shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},...@@ -63,7 +68,10 @@ shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
63shstrtab_index: ?u16 = null,68shstrtab_index: ?u16 = null,
6469
65symtab_section_index: ?u16 = null,70symtab_section_index: ?u16 = null,
71text_section_index: ?u16 = null,
72rodata_section_index: ?u16 = null,
66got_section_index: ?u16 = null,73got_section_index: ?u16 = null,
74data_section_index: ?u16 = null,
67debug_info_section_index: ?u16 = null,75debug_info_section_index: ?u16 = null,
68debug_abbrev_section_index: ?u16 = null,76debug_abbrev_section_index: ?u16 = null,
69debug_str_section_index: ?u16 = null,77debug_str_section_index: ?u16 = null,
...@@ -116,8 +124,9 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},...@@ -116,8 +124,9 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},
116/// overcapacity can be negative. A simple way to have negative overcapacity is to124/// overcapacity can be negative. A simple way to have negative overcapacity is to
117/// allocate a fresh text block, which will have ideal capacity, and then grow it125/// allocate a fresh text block, which will have ideal capacity, and then grow it
118/// by 1 byte. It will then have -1 overcapacity.126/// by 1 byte. It will then have -1 overcapacity.
119text_block_list: TextBlockList = .{},127atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{},
120rodata_block_list: TextBlockList = .{},128atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{},
129decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{},
121130
122/// A list of `SrcFn` whose Line Number Programs have surplus capacity.131/// A list of `SrcFn` whose Line Number Programs have surplus capacity.
123/// This is the same concept as `text_block_free_list`; see those doc comments.132/// This is the same concept as `text_block_free_list`; see those doc comments.
...@@ -205,14 +214,6 @@ pub const TextBlock = struct {...@@ -205,14 +214,6 @@ pub const TextBlock = struct {
205 }214 }
206};215};
207216
208/// A list of text blocks in a specific section
209const 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
216pub const Export = struct {217pub const Export = struct {
217 sym_index: ?u32 = null,218 sym_index: ?u32 = null,
218};219};
...@@ -326,11 +327,20 @@ pub fn deinit(self: *Elf) void {...@@ -326,11 +327,20 @@ pub fn deinit(self: *Elf) void {
326 self.global_symbol_free_list.deinit(self.base.allocator);327 self.global_symbol_free_list.deinit(self.base.allocator);
327 self.local_symbol_free_list.deinit(self.base.allocator);328 self.local_symbol_free_list.deinit(self.base.allocator);
328 self.offset_table_free_list.deinit(self.base.allocator);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 self.dbg_line_fn_free_list.deinit(self.base.allocator);330 self.dbg_line_fn_free_list.deinit(self.base.allocator);
332 self.dbg_info_decl_free_list.deinit(self.base.allocator);331 self.dbg_info_decl_free_list.deinit(self.base.allocator);
333 self.offset_table.deinit(self.base.allocator);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}
335345
336pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {346pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {
...@@ -463,11 +473,10 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -463,11 +473,10 @@ pub fn populateMissingMetadata(self: *Elf) !void {
463 const ptr_size: u8 = self.ptrWidthBytes();473 const ptr_size: u8 = self.ptrWidthBytes();
464 if (self.phdr_load_re_index == null) {474 if (self.phdr_load_re_index == null) {
465 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);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 const file_size = self.base.options.program_code_size_hint;476 const file_size = self.base.options.program_code_size_hint;
468 const p_align = 0x1000;477 const p_align = 0x1000;
469 const off = self.findFreeSpace(file_size, p_align);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 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;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 try self.program_headers.append(self.base.allocator, .{481 try self.program_headers.append(self.base.allocator, .{
473 .p_type = elf.PT_LOAD,482 .p_type = elf.PT_LOAD,
...@@ -479,6 +488,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -479,6 +488,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
479 .p_align = p_align,488 .p_align = p_align,
480 .p_flags = elf.PF_X | elf.PF_R,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 self.entry_addr = null;492 self.entry_addr = null;
483 self.phdr_table_dirty = true;493 self.phdr_table_dirty = true;
484 }494 }
...@@ -489,7 +499,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -489,7 +499,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
489 // page align.499 // page align.
490 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);500 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
491 const off = self.findFreeSpace(file_size, p_align);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 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.503 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
494 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something504 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
495 // else in virtual memory.505 // else in virtual memory.
...@@ -508,15 +518,14 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -508,15 +518,14 @@ pub fn populateMissingMetadata(self: *Elf) !void {
508 }518 }
509 if (self.phdr_load_ro_index == null) {519 if (self.phdr_load_ro_index == null) {
510 self.phdr_load_ro_index = @intCast(u16, self.program_headers.items.len);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 // TODO Find a hint about how much data need to be in rodata ?521 // TODO Find a hint about how much data need to be in rodata ?
513 const file_size = 1024;522 const file_size = 1024;
514 // Same reason as for GOT523 // Same reason as for GOT
515 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);524 const p_align = if (self.base.options.target.os.tag == .linux) 0x1000 else @as(u16, ptr_size);
516 const off = self.findFreeSpace(file_size, p_align);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 // TODO Same as for GOT527 // 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 try self.program_headers.append(self.base.allocator, .{529 try self.program_headers.append(self.base.allocator, .{
521 .p_type = elf.PT_LOAD,530 .p_type = elf.PT_LOAD,
522 .p_offset = off,531 .p_offset = off,
...@@ -527,6 +536,30 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -527,6 +536,30 @@ pub fn populateMissingMetadata(self: *Elf) !void {
527 .p_align = p_align,536 .p_align = p_align,
528 .p_flags = elf.PF_R,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 self.phdr_table_dirty = true;563 self.phdr_table_dirty = true;
531 }564 }
532 if (self.shstrtab_index == null) {565 if (self.shstrtab_index == null) {
...@@ -550,8 +583,8 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -550,8 +583,8 @@ pub fn populateMissingMetadata(self: *Elf) !void {
550 self.shstrtab_dirty = true;583 self.shstrtab_dirty = true;
551 self.shdr_table_dirty = true;584 self.shdr_table_dirty = true;
552 }585 }
553 if (self.text_block_list.section_index == null) {586 if (self.text_section_index == null) {
554 self.text_block_list.section_index = @intCast(u16, self.sections.items.len);587 self.text_section_index = @intCast(u16, self.sections.items.len);
555 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];588 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
556589
557 try self.sections.append(self.base.allocator, .{590 try self.sections.append(self.base.allocator, .{
...@@ -566,6 +599,11 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -566,6 +599,11 @@ pub fn populateMissingMetadata(self: *Elf) !void {
566 .sh_addralign = phdr.p_align,599 .sh_addralign = phdr.p_align,
567 .sh_entsize = 0,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 self.shdr_table_dirty = true;607 self.shdr_table_dirty = true;
570 }608 }
571 if (self.got_section_index == null) {609 if (self.got_section_index == null) {
...@@ -584,10 +622,15 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -584,10 +622,15 @@ pub fn populateMissingMetadata(self: *Elf) !void {
584 .sh_addralign = phdr.p_align,622 .sh_addralign = phdr.p_align,
585 .sh_entsize = 0,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 self.shdr_table_dirty = true;630 self.shdr_table_dirty = true;
588 }631 }
589 if (self.rodata_block_list.section_index == null) {632 if (self.rodata_section_index == null) {
590 self.rodata_block_list.section_index = @intCast(u16, self.sections.items.len);633 self.rodata_section_index = @intCast(u16, self.sections.items.len);
591 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];634 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];
592635
593 try self.sections.append(self.base.allocator, .{636 try self.sections.append(self.base.allocator, .{
...@@ -602,6 +645,34 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -602,6 +645,34 @@ pub fn populateMissingMetadata(self: *Elf) !void {
602 .sh_addralign = phdr.p_align,645 .sh_addralign = phdr.p_align,
603 .sh_entsize = 0,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 self.shdr_table_dirty = true;676 self.shdr_table_dirty = true;
606 }677 }
607 if (self.symtab_section_index == null) {678 if (self.symtab_section_index == null) {
...@@ -2072,17 +2143,18 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2072,17 +2143,18 @@ fn writeElfHeader(self: *Elf) !void {
2072 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2143 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
2073}2144}
20742145
2075fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock) void {2146fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2147 const free_list = self.atom_free_lists.getPtr(phdr_index).?;
2076 var already_have_free_list_node = false;2148 var already_have_free_list_node = false;
2077 {2149 {
2078 var i: usize = 0;2150 var i: usize = 0;
2079 // TODO turn text_block_free_list into a hash map2151 // TODO turn free_list into a hash map
2080 while (i < block_list.free_list.items.len) {2152 while (i < free_list.items.len) {
2081 if (block_list.free_list.items[i] == text_block) {2153 if (free_list.items[i] == text_block) {
2082 _ = block_list.free_list.swapRemove(i);2154 _ = free_list.swapRemove(i);
2083 continue;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 already_have_free_list_node = true;2158 already_have_free_list_node = true;
2087 }2159 }
2088 i += 1;2160 i += 1;
...@@ -2090,10 +2162,17 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock)...@@ -2090,10 +2162,17 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock)
2090 }2162 }
2091 // TODO process free list for dbg info just like we do above for vaddrs2163 // TODO process free list for dbg info just like we do above for vaddrs
20922164
2093 if (block_list.last_block == text_block) {2165 if (self.atoms.getPtr(phdr_index)) |last_block| {
2094 // TODO shrink the .text section size here2166 if (last_block.* == text_block) {
2095 block_list.last_block = text_block.prev;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 if (self.dbg_info_decl_first == text_block) {2176 if (self.dbg_info_decl_first == text_block) {
2098 self.dbg_info_decl_first = text_block.dbg_info_next;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,7 +2187,7 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock)
2108 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {2187 if (!already_have_free_list_node and prev.freeListEligible(self.*)) {
2109 // The free list is heuristics, it doesn't have to be perfect, so we can2188 // The free list is heuristics, it doesn't have to be perfect, so we can
2110 // ignore the OOM here.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 } else {2192 } else {
2114 text_block.prev = null;2193 text_block.prev = null;
...@@ -2135,24 +2214,25 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock)...@@ -2135,24 +2214,25 @@ fn freeTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock)
2135 }2214 }
2136}2215}
21372216
2138fn shrinkTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64) void {2217fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr_index: u16) void {
2139 _ = self;2218 _ = self;
2140 _ = block_list;
2141 _ = text_block;2219 _ = text_block;
2142 _ = new_block_size;2220 _ = new_block_size;
2221 _ = phdr_index;
2143}2222}
21442223
2145fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {2224fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2146 const sym = self.local_symbols.items[text_block.local_sym_index];2225 const sym = self.local_symbols.items[text_block.local_sym_index];
2147 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;2226 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
2148 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);2227 const need_realloc = !align_ok or new_block_size > text_block.capacity(self.*);
2149 if (!need_realloc) return sym.st_value;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}
21522231
2153fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {2232fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2154 const phdr = &self.program_headers.items[block_list.phdr_index.?];2233 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2155 const shdr = &self.sections.items[block_list.section_index.?];2234 const phdr = &self.program_headers.items[phdr_index];
2235 const shdr = &self.sections.items[shdr_index];
2156 const new_block_ideal_capacity = padToIdeal(new_block_size);2236 const new_block_ideal_capacity = padToIdeal(new_block_size);
21572237
2158 // We use these to indicate our intention to update metadata, placing the new block,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,13 +2242,14 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2162 // is actually carried out at the end of the function, when errors are no longer possible.2242 // is actually carried out at the end of the function, when errors are no longer possible.
2163 var block_placement: ?*TextBlock = null;2243 var block_placement: ?*TextBlock = null;
2164 var free_list_removal: ?usize = null;2244 var free_list_removal: ?usize = null;
2245 var free_list = self.atom_free_lists.get(phdr_index).?;
21652246
2166 // First we look for an appropriately sized free list node.2247 // First we look for an appropriately sized free list node.
2167 // The list is unordered. We'll just take the first thing that works.2248 // The list is unordered. We'll just take the first thing that works.
2168 const vaddr = blk: {2249 const vaddr = blk: {
2169 var i: usize = 0;2250 var i: usize = 0;
2170 while (i < block_list.free_list.items.len) {2251 while (i < free_list.items.len) {
2171 const big_block = block_list.free_list.items[i];2252 const big_block = free_list.items[i];
2172 // We now have a pointer to a live text block that has too much capacity.2253 // We now have a pointer to a live text block that has too much capacity.
2173 // Is it enough that we could fit this new text block?2254 // Is it enough that we could fit this new text block?
2174 const sym = self.local_symbols.items[big_block.local_sym_index];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,7 +2264,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2183 // should be deleted because the block that it points to has grown to take up2264 // should be deleted because the block that it points to has grown to take up
2184 // more of the extra capacity.2265 // more of the extra capacity.
2185 if (!big_block.freeListEligible(self.*)) {2266 if (!big_block.freeListEligible(self.*)) {
2186 _ = block_list.free_list.swapRemove(i);2267 _ = free_list.swapRemove(i);
2187 } else {2268 } else {
2188 i += 1;2269 i += 1;
2189 }2270 }
...@@ -2201,7 +2282,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl...@@ -2201,7 +2282,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2201 free_list_removal = i;2282 free_list_removal = i;
2202 }2283 }
2203 break :blk new_start_vaddr;2284 break :blk new_start_vaddr;
2204 } else if (block_list.last_block) |last| {2285 } else if (self.atoms.get(phdr_index)) |last| {
2205 const sym = self.local_symbols.items[last.local_sym_index];2286 const sym = self.local_symbols.items[last.local_sym_index];
2206 const ideal_capacity = padToIdeal(sym.st_size);2287 const ideal_capacity = padToIdeal(sym.st_size);
2207 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;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,7 +2302,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2221 if (needed_size > text_capacity) {2302 if (needed_size > text_capacity) {
2222 // Must move the entire text section.2303 // Must move the entire text section.
2223 const new_offset = self.findFreeSpace(needed_size, 0x1000);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 const sym = self.local_symbols.items[last.local_sym_index];2306 const sym = self.local_symbols.items[last.local_sym_index];
2226 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;2307 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
2227 } else 0;2308 } else 0;
...@@ -2230,7 +2311,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl...@@ -2230,7 +2311,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2230 shdr.sh_offset = new_offset;2311 shdr.sh_offset = new_offset;
2231 phdr.p_offset = new_offset;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);
22342315
2235 shdr.sh_size = needed_size;2316 shdr.sh_size = needed_size;
2236 phdr.p_memsz = needed_size;2317 phdr.p_memsz = needed_size;
...@@ -2268,19 +2349,11 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl...@@ -2268,19 +2349,11 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl
2268 text_block.next = null;2349 text_block.next = null;
2269 }2350 }
2270 if (free_list_removal) |i| {2351 if (free_list_removal) |i| {
2271 _ = block_list.free_list.swapRemove(i);2352 _ = free_list.swapRemove(i);
2272 }2353 }
2273 return vaddr;2354 return vaddr;
2274}2355}
22752356
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
2278fn 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
2284pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {2357pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
2285 if (self.llvm_object) |_| return;2358 if (self.llvm_object) |_| return;
22862359
...@@ -2288,6 +2361,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {...@@ -2288,6 +2361,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
22882361
2289 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);2362 try self.local_symbols.ensureUnusedCapacity(self.base.allocator, 1);
2290 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);2363 try self.offset_table.ensureUnusedCapacity(self.base.allocator, 1);
2364 try self.decls.putNoClobber(self.base.allocator, decl, null);
22912365
2292 if (self.local_symbol_free_list.popOrNull()) |i| {2366 if (self.local_symbol_free_list.popOrNull()) |i| {
2293 log.debug("reusing symbol index {d} for {s}", .{ i, decl.name });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,14 +2380,12 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
2306 self.offset_table_count_dirty = true;2380 self.offset_table_count_dirty = true;
2307 }2381 }
23082382
2309 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
2310
2311 self.local_symbols.items[decl.link.elf.local_sym_index] = .{2383 self.local_symbols.items[decl.link.elf.local_sym_index] = .{
2312 .st_name = 0,2384 .st_name = 0,
2313 .st_info = 0,2385 .st_info = 0,
2314 .st_other = 0,2386 .st_other = 0,
2315 .st_shndx = 0,2387 .st_shndx = 0,
2316 .st_value = phdr.p_vaddr,2388 .st_value = 0,
2317 .st_size = 0,2389 .st_size = 0,
2318 };2390 };
2319 self.offset_table.items[decl.link.elf.offset_table_index] = 0;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,10 +2396,12 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
2324 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl);2396 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl);
2325 }2397 }
23262398
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 }
23282403
2329 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.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 if (decl.link.elf.local_sym_index != 0) {2405 if (decl.link.elf.local_sym_index != 0) {
2332 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};2406 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
2333 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};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,11 +2440,39 @@ fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
2366 table.deinit(gpa);2440 table.deinit(gpa);
2367}2441}
23682442
2443fn 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
2369fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {2466fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
2370 log.debug("updateDeclCode {s}{*}", .{ mem.sliceTo(decl.name, 0), decl });2467 log.debug("updateDeclCode {s}{*}", .{ mem.sliceTo(decl.name, 0), decl });
2371 const required_alignment = decl.ty.abiAlignment(self.base.options.target);2468 const required_alignment = decl.ty.abiAlignment(self.base.options.target);
23722469
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).?;
23742476
2375 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()2477 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
2376 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];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,7 +2481,7 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8
2379 const need_realloc = code.len > capacity or2481 const need_realloc = code.len > capacity or
2380 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);2482 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2381 if (need_realloc) {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 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr });2485 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr });
2384 if (vaddr != local_sym.st_value) {2486 if (vaddr != local_sym.st_value) {
2385 local_sym.st_value = vaddr;2487 local_sym.st_value = vaddr;
...@@ -2389,28 +2491,28 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8...@@ -2389,28 +2491,28 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8
2389 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);2491 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2390 }2492 }
2391 } else if (code.len < local_sym.st_size) {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 local_sym.st_size = code.len;2496 local_sym.st_size = code.len;
2395 local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0));2497 local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0));
2396 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;2498 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2397 local_sym.st_other = 0;2499 local_sym.st_other = 0;
2398 local_sym.st_shndx = block_list.section_index.?;2500 local_sym.st_shndx = shdr_index;
2399 // TODO this write could be avoided if no fields of the symbol were changed.2501 // TODO this write could be avoided if no fields of the symbol were changed.
2400 try self.writeSymbol(decl.link.elf.local_sym_index);2502 try self.writeSymbol(decl.link.elf.local_sym_index);
2401 } else {2503 } else {
2402 const decl_name = mem.sliceTo(decl.name, 0);2504 const decl_name = mem.sliceTo(decl.name, 0);
2403 const name_str_index = try self.makeString(decl_name);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);2506 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);
2405 errdefer self.freeTextBlock(block_list, &decl.link.elf);2507 errdefer self.freeTextBlock(&decl.link.elf, phdr_index);
2406 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });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);
24082510
2409 local_sym.* = .{2511 local_sym.* = .{
2410 .st_name = name_str_index,2512 .st_name = name_str_index,
2411 .st_info = (elf.STB_LOCAL << 4) | stt_bits,2513 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
2412 .st_other = 0,2514 .st_other = 0,
2413 .st_shndx = block_list.section_index.?,2515 .st_shndx = shdr_index,
2414 .st_value = vaddr,2516 .st_value = vaddr,
2415 .st_size = code.len,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,8 +2522,8 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8
2420 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);2522 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2421 }2523 }
24222524
2423 const section_offset = local_sym.st_value - self.program_headers.items[block_list.phdr_index.?].p_vaddr;2525 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2424 const file_offset = self.sections.items[block_list.section_index.?].sh_offset + section_offset;2526 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;
2425 try self.base.file.?.pwriteAll(code, file_offset);2527 try self.base.file.?.pwriteAll(code, file_offset);
24262528
2427 return local_sym;2529 return local_sym;
...@@ -3008,7 +3110,12 @@ pub fn updateDeclExports(...@@ -3008,7 +3110,12 @@ pub fn updateDeclExports(
3008 if (decl.link.elf.local_sym_index == 0) return;3110 if (decl.link.elf.local_sym_index == 0) return;
3009 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];3111 const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
30103112
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).?;
30123119
3013 for (exports) |exp| {3120 for (exports) |exp| {
3014 if (exp.options.section) |section_name| {3121 if (exp.options.section) |section_name| {
...@@ -3047,7 +3154,7 @@ pub fn updateDeclExports(...@@ -3047,7 +3154,7 @@ pub fn updateDeclExports(
3047 .st_name = try self.updateString(sym.st_name, exp.options.name),3154 .st_name = try self.updateString(sym.st_name, exp.options.name),
3048 .st_info = (stb_bits << 4) | stt_bits,3155 .st_info = (stb_bits << 4) | stt_bits,
3049 .st_other = 0,3156 .st_other = 0,
3050 .st_shndx = block_list.section_index.?,3157 .st_shndx = shdr_index,
3051 .st_value = decl_sym.st_value,3158 .st_value = decl_sym.st_value,
3052 .st_size = decl_sym.st_size,3159 .st_size = decl_sym.st_size,
3053 };3160 };
...@@ -3061,7 +3168,7 @@ pub fn updateDeclExports(...@@ -3061,7 +3168,7 @@ pub fn updateDeclExports(
3061 .st_name = name,3168 .st_name = name,
3062 .st_info = (stb_bits << 4) | stt_bits,3169 .st_info = (stb_bits << 4) | stt_bits,
3063 .st_other = 0,3170 .st_other = 0,
3064 .st_shndx = block_list.section_index.?,3171 .st_shndx = shdr_index,
3065 .st_value = decl_sym.st_value,3172 .st_value = decl_sym.st_value,
3066 .st_size = decl_sym.st_size,3173 .st_size = decl_sym.st_size,
3067 };3174 };
test/behavior.zig+1-1
...@@ -14,6 +14,7 @@ test {...@@ -14,6 +14,7 @@ test {
14 _ = @import("behavior/bugs/1277.zig");14 _ = @import("behavior/bugs/1277.zig");
15 _ = @import("behavior/bugs/1310.zig");15 _ = @import("behavior/bugs/1310.zig");
16 _ = @import("behavior/bugs/1381.zig");16 _ = @import("behavior/bugs/1381.zig");
17 _ = @import("behavior/bugs/1486.zig");
17 _ = @import("behavior/bugs/1500.zig");18 _ = @import("behavior/bugs/1500.zig");
18 _ = @import("behavior/bugs/1735.zig");19 _ = @import("behavior/bugs/1735.zig");
19 _ = @import("behavior/bugs/2006.zig");20 _ = @import("behavior/bugs/2006.zig");
...@@ -43,7 +44,6 @@ test {...@@ -43,7 +44,6 @@ test {
43 _ = @import("behavior/bugs/624.zig");44 _ = @import("behavior/bugs/624.zig");
44 _ = @import("behavior/bugs/704.zig");45 _ = @import("behavior/bugs/704.zig");
45 _ = @import("behavior/bugs/1076.zig");46 _ = @import("behavior/bugs/1076.zig");
46 _ = @import("behavior/bugs/1486.zig");
47 _ = @import("behavior/bugs/2692.zig");47 _ = @import("behavior/bugs/2692.zig");
48 _ = @import("behavior/bugs/2889.zig");48 _ = @import("behavior/bugs/2889.zig");
49 _ = @import("behavior/bugs/3046.zig");49 _ = @import("behavior/bugs/3046.zig");
test/behavior/bugs/1486.zig+6-2
...@@ -1,9 +1,13 @@...@@ -1,9 +1,13 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
24
3const ptr = &global;5const ptr = &global;
4var global: u64 = 123;6var global: usize = 123;
57
6test "constant pointer to global variable causes runtime load" {8test "constant pointer to global variable causes runtime load" {
9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
10
7 global = 1234;11 global = 1234;
8 try expect(&global == ptr);12 try expect(&global == ptr);
9 try expect(ptr.* == 1234);13 try expect(ptr.* == 1234);