authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-23 11:59:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-23 17:15:41+02:00
log29ebd96818bce4c4f2842d1bb76390247d47e198
tree9ffd3b6089dee7eb4b3abd5b14775f541f04c461
parent9f05cb318b77c18c312592cba52c782d70f2432f

elf: improve decl-to-section mapping logic


5 files changed, 200 insertions(+), 129 deletions(-)

src/link/Elf.zig+174-111
...@@ -415,16 +415,19 @@ const AllocateSegmentOpts = struct {...@@ -415,16 +415,19 @@ const AllocateSegmentOpts = struct {
415 flags: u32 = elf.PF_R,415 flags: u32 = elf.PF_R,
416};416};
417417
418fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) !u16 {418fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 {
419 const index = @as(u16, @intCast(self.phdrs.items.len));419 const index = @as(u16, @intCast(self.phdrs.items.len));
420 try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1);420 try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1);
421 const off = self.findFreeSpace(opts.size, opts.alignment);421 const off = self.findFreeSpace(opts.size, opts.alignment);
422 log.debug("found PHDR {c}{c}{c} free space 0x{x} to 0x{x}", .{422 log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
423 index,
423 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',424 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',
424 if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_',425 if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_',
425 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',426 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',
426 off,427 off,
427 off + opts.size,428 off + opts.size,
429 opts.addr,
430 opts.addr + opts.size,
428 });431 });
429 self.phdrs.appendAssumeCapacity(.{432 self.phdrs.appendAssumeCapacity(.{
430 .p_type = elf.PT_LOAD,433 .p_type = elf.PT_LOAD,
...@@ -440,6 +443,45 @@ fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) !u16 {...@@ -440,6 +443,45 @@ fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) !u16 {
440 return index;443 return index;
441}444}
442445
446const AllocateAllocSectionOpts = struct {
447 name: [:0]const u8,
448 phdr_index: u16,
449 alignment: u16 = 1,
450 flags: u16 = elf.SHF_ALLOC,
451 type: u32 = elf.SHT_PROGBITS,
452};
453
454fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{OutOfMemory}!u16 {
455 const gpa = self.base.allocator;
456 const phdr = &self.phdrs.items[opts.phdr_index];
457 const index = @as(u16, @intCast(self.shdrs.items.len));
458 try self.shdrs.ensureUnusedCapacity(gpa, 1);
459 const sh_name = try self.shstrtab.insert(gpa, opts.name);
460 try self.phdr_to_shdr_table.putNoClobber(gpa, index, opts.phdr_index);
461 log.debug("allocating '{s}' in PHDR({d}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
462 opts.name,
463 opts.phdr_index,
464 phdr.p_offset,
465 phdr.p_offset + phdr.p_filesz,
466 phdr.p_vaddr,
467 phdr.p_vaddr + phdr.p_memsz,
468 });
469 self.shdrs.appendAssumeCapacity(.{
470 .sh_name = sh_name,
471 .sh_type = opts.type,
472 .sh_flags = opts.flags,
473 .sh_addr = phdr.p_vaddr,
474 .sh_offset = phdr.p_offset,
475 .sh_size = phdr.p_filesz,
476 .sh_link = 0,
477 .sh_info = 0,
478 .sh_addralign = opts.alignment,
479 .sh_entsize = 0,
480 });
481 self.shdr_table_dirty = true;
482 return index;
483}
484
443pub fn populateMissingMetadata(self: *Elf) !void {485pub fn populateMissingMetadata(self: *Elf) !void {
444 const gpa = self.base.allocator;486 const gpa = self.base.allocator;
445 const small_ptr = switch (self.ptr_width) {487 const small_ptr = switch (self.ptr_width) {
...@@ -545,6 +587,8 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -545,6 +587,8 @@ pub fn populateMissingMetadata(self: *Elf) !void {
545 .alignment = alignment,587 .alignment = alignment,
546 .flags = elf.PF_R | elf.PF_W,588 .flags = elf.PF_R | elf.PF_W,
547 });589 });
590 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];
591 phdr.p_offset = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; // .bss overlaps .data
548 }592 }
549593
550 if (self.shstrtab_section_index == null) {594 if (self.shstrtab_section_index == null) {
...@@ -592,102 +636,49 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -592,102 +636,49 @@ pub fn populateMissingMetadata(self: *Elf) !void {
592 }636 }
593637
594 if (self.text_section_index == null) {638 if (self.text_section_index == null) {
595 self.text_section_index = @intCast(self.shdrs.items.len);639 self.text_section_index = try self.allocateAllocSection(.{
596 const phdr = &self.phdrs.items[self.phdr_load_re_index.?];640 .name = ".text",
597 try self.shdrs.append(gpa, .{641 .phdr_index = self.phdr_load_re_index.?,
598 .sh_name = try self.shstrtab.insert(gpa, ".text"),642 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
599 .sh_type = elf.SHT_PROGBITS,
600 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
601 .sh_addr = phdr.p_vaddr,
602 .sh_offset = phdr.p_offset,
603 .sh_size = phdr.p_filesz,
604 .sh_link = 0,
605 .sh_info = 0,
606 .sh_addralign = 1,
607 .sh_entsize = 0,
608 });643 });
609 try self.phdr_to_shdr_table.putNoClobber(gpa, self.text_section_index.?, self.phdr_load_re_index.?);
610 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.text_section_index.?, .{});644 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.text_section_index.?, .{});
611 self.shdr_table_dirty = true;
612 }645 }
613646
614 if (self.got_section_index == null) {647 if (self.got_section_index == null) {
615 self.got_section_index = @intCast(self.shdrs.items.len);648 self.got_section_index = try self.allocateAllocSection(.{
616 const phdr = &self.phdrs.items[self.phdr_got_index.?];649 .name = ".got",
617 try self.shdrs.append(gpa, .{650 .phdr_index = self.phdr_got_index.?,
618 .sh_name = try self.shstrtab.insert(gpa, ".got"),651 .alignment = ptr_size,
619 .sh_type = elf.SHT_PROGBITS,
620 .sh_flags = elf.SHF_ALLOC,
621 .sh_addr = phdr.p_vaddr,
622 .sh_offset = phdr.p_offset,
623 .sh_size = phdr.p_filesz,
624 .sh_link = 0,
625 .sh_info = 0,
626 .sh_addralign = @as(u16, ptr_size),
627 .sh_entsize = 0,
628 });652 });
629 try self.phdr_to_shdr_table.putNoClobber(gpa, self.got_section_index.?, self.phdr_got_index.?);
630 self.shdr_table_dirty = true;
631 }653 }
632654
633 if (self.rodata_section_index == null) {655 if (self.rodata_section_index == null) {
634 self.rodata_section_index = @intCast(self.shdrs.items.len);656 self.rodata_section_index = try self.allocateAllocSection(.{
635 const phdr = &self.phdrs.items[self.phdr_load_ro_index.?];657 .name = ".rodata",
636 try self.shdrs.append(gpa, .{658 .phdr_index = self.phdr_load_ro_index.?,
637 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
638 .sh_type = elf.SHT_PROGBITS,
639 .sh_flags = elf.SHF_ALLOC,
640 .sh_addr = phdr.p_vaddr,
641 .sh_offset = phdr.p_offset,
642 .sh_size = phdr.p_filesz,
643 .sh_link = 0,
644 .sh_info = 0,
645 .sh_addralign = 1,
646 .sh_entsize = 0,
647 });659 });
648 try self.phdr_to_shdr_table.putNoClobber(gpa, self.rodata_section_index.?, self.phdr_load_ro_index.?);
649 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.rodata_section_index.?, .{});660 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.rodata_section_index.?, .{});
650 self.shdr_table_dirty = true;
651 }661 }
652662
653 if (self.data_section_index == null) {663 if (self.data_section_index == null) {
654 self.data_section_index = @intCast(self.shdrs.items.len);664 self.data_section_index = try self.allocateAllocSection(.{
655 const phdr = &self.phdrs.items[self.phdr_load_rw_index.?];665 .name = ".data",
656 try self.shdrs.append(gpa, .{666 .phdr_index = self.phdr_load_rw_index.?,
657 .sh_name = try self.shstrtab.insert(gpa, ".data"),667 .alignment = ptr_size,
658 .sh_type = elf.SHT_PROGBITS,668 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
659 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
660 .sh_addr = phdr.p_vaddr,
661 .sh_offset = phdr.p_offset,
662 .sh_size = phdr.p_filesz,
663 .sh_link = 0,
664 .sh_info = 0,
665 .sh_addralign = @as(u16, ptr_size),
666 .sh_entsize = 0,
667 });669 });
668 try self.phdr_to_shdr_table.putNoClobber(gpa, self.data_section_index.?, self.phdr_load_rw_index.?);
669 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.data_section_index.?, .{});670 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.data_section_index.?, .{});
670 self.shdr_table_dirty = true;
671 }671 }
672672
673 if (self.bss_section_index == null) {673 if (self.bss_section_index == null) {
674 self.bss_section_index = @intCast(self.shdrs.items.len);674 self.bss_section_index = try self.allocateAllocSection(.{
675 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];675 .name = ".bss",
676 try self.shdrs.append(gpa, .{676 .phdr_index = self.phdr_load_zerofill_index.?,
677 .sh_name = try self.shstrtab.insert(gpa, ".bss"),677 .alignment = ptr_size,
678 .sh_type = elf.SHT_NOBITS,678 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
679 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,679 .type = elf.SHT_NOBITS,
680 .sh_addr = phdr.p_vaddr,
681 .sh_offset = phdr.p_offset,
682 .sh_size = phdr.p_filesz,
683 .sh_link = 0,
684 .sh_info = 0,
685 .sh_addralign = @as(u16, ptr_size),
686 .sh_entsize = 0,
687 });680 });
688 try self.phdr_to_shdr_table.putNoClobber(gpa, self.bss_section_index.?, self.phdr_load_zerofill_index.?);
689 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{});681 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{});
690 self.shdr_table_dirty = true;
691 }682 }
692683
693 if (self.symtab_section_index == null) {684 if (self.symtab_section_index == null) {
...@@ -1154,7 +1145,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1154,7 +1145,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1154 for (self.file(index).?.zig_module.atoms.keys()) |atom_index| {1145 for (self.file(index).?.zig_module.atoms.keys()) |atom_index| {
1155 const atom_ptr = self.atom(atom_index).?;1146 const atom_ptr = self.atom(atom_index).?;
1156 if (!atom_ptr.alive) continue;1147 if (!atom_ptr.alive) continue;
1157 const shdr = &self.shdrs.items[atom_ptr.output_section_index];1148 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
1158 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;1149 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1159 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;1150 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1160 const code = try gpa.alloc(u8, size);1151 const code = try gpa.alloc(u8, size);
...@@ -1184,6 +1175,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1184,6 +1175,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1184 try self.updateSymtabSize();1175 try self.updateSymtabSize();
1185 try self.writeSymtab();1176 try self.writeSymtab();
11861177
1178 // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't
1179 // get mapped by the loader
1180 if (self.data_section_index) |data_shndx| blk: {
1181 const bss_shndx = self.bss_section_index orelse break :blk;
1182 const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?;
1183 const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?;
1184 self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset;
1185 self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset;
1186 }
1187
1187 // Dump the state for easy debugging.1188 // Dump the state for easy debugging.
1188 // State can be dumped via `--debug-log link_state`.1189 // State can be dumped via `--debug-log link_state`.
1189 if (build_options.enable_logging) {1190 if (build_options.enable_logging) {
...@@ -1683,7 +1684,7 @@ fn writeObjects(self: *Elf) !void {...@@ -1683,7 +1684,7 @@ fn writeObjects(self: *Elf) !void {
1683 const atom_ptr = self.atom(atom_index) orelse continue;1684 const atom_ptr = self.atom(atom_index) orelse continue;
1684 if (!atom_ptr.alive) continue;1685 if (!atom_ptr.alive) continue;
16851686
1686 const shdr = &self.shdrs.items[atom_ptr.output_section_index];1687 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
1687 if (shdr.sh_type == elf.SHT_NOBITS) continue;1688 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1688 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections1689 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections
16891690
...@@ -2557,15 +2558,15 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2557,15 +2558,15 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
2557 }2558 }
2558}2559}
25592560
2560pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !Symbol.Index {2561pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymbol) !Symbol.Index {
2561 const mod = self.base.options.module.?;2562 const mod = self.base.options.module.?;
2562 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod));2563 const gop = try self.lazy_syms.getOrPut(self.base.allocator, lazy_sym.getDecl(mod));
2563 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();2564 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
2564 if (!gop.found_existing) gop.value_ptr.* = .{};2565 if (!gop.found_existing) gop.value_ptr.* = .{};
2565 const metadata: struct {2566 const metadata: struct {
2566 symbol_index: *Symbol.Index,2567 symbol_index: *Symbol.Index,
2567 state: *LazySymbolMetadata.State,2568 state: *LazySymbolMetadata.State,
2568 } = switch (sym.kind) {2569 } = switch (lazy_sym.kind) {
2569 .code => .{2570 .code => .{
2570 .symbol_index = &gop.value_ptr.text_symbol_index,2571 .symbol_index = &gop.value_ptr.text_symbol_index,
2571 .state = &gop.value_ptr.text_state,2572 .state = &gop.value_ptr.text_state,
...@@ -2577,17 +2578,14 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !...@@ -2577,17 +2578,14 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !
2577 };2578 };
2578 const zig_module = self.file(self.zig_module_index.?).?.zig_module;2579 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
2579 switch (metadata.state.*) {2580 switch (metadata.state.*) {
2580 .unused => metadata.symbol_index.* = try zig_module.addAtom(switch (sym.kind) {2581 .unused => metadata.symbol_index.* = try zig_module.addAtom(self),
2581 .code => self.text_section_index.?,
2582 .const_data => self.rodata_section_index.?,
2583 }, self),
2584 .pending_flush => return metadata.symbol_index.*,2582 .pending_flush => return metadata.symbol_index.*,
2585 .flushed => {},2583 .flushed => {},
2586 }2584 }
2587 metadata.state.* = .pending_flush;2585 metadata.state.* = .pending_flush;
2588 const symbol_index = metadata.symbol_index.*;2586 const symbol_index = metadata.symbol_index.*;
2589 // anyerror needs to be deferred until flushModule2587 // anyerror needs to be deferred until flushModule
2590 if (sym.getDecl(mod) != .none) try self.updateLazySymbol(sym, symbol_index);2588 if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(lazy_sym, symbol_index);
2591 return symbol_index;2589 return symbol_index;
2592}2590}
25932591
...@@ -2596,35 +2594,37 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy...@@ -2596,35 +2594,37 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy
2596 if (!gop.found_existing) {2594 if (!gop.found_existing) {
2597 const zig_module = self.file(self.zig_module_index.?).?.zig_module;2595 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
2598 gop.value_ptr.* = .{2596 gop.value_ptr.* = .{
2599 .symbol_index = try zig_module.addAtom(self.getDeclShdrIndex(decl_index), self),2597 .symbol_index = try zig_module.addAtom(self),
2600 .exports = .{},2598 .exports = .{},
2601 };2599 };
2602 }2600 }
2603 return gop.value_ptr.symbol_index;2601 return gop.value_ptr.symbol_index;
2604}2602}
26052603
2606fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 {2604fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 {
2607 const mod = self.base.options.module.?;2605 const mod = self.base.options.module.?;
2608 const decl = mod.declPtr(decl_index);2606 const decl = mod.declPtr(decl_index);
2609 const ty = decl.ty;2607 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
2610 const zig_ty = ty.zigTypeTag(mod);2608 // TODO: what if this is a function pointer?
2611 const val = decl.val;2609 .Fn => self.text_section_index.?,
2612 const shdr_index: u16 = blk: {2610 else => blk: {
2613 if (val.isUndefDeep(mod)) {2611 if (decl.getOwnedVariable(mod)) |variable| {
2614 // TODO in release-fast and release-small, we should put undef in .bss2612 if (variable.is_const) break :blk self.rodata_section_index.?;
2615 break :blk self.data_section_index.?;2613 if (variable.init.toValue().isUndefDeep(mod)) {
2616 }2614 const mode = self.base.options.optimize_mode;
26172615 if (mode == .Debug or mode == .ReleaseSafe) break :blk self.data_section_index.?;
2618 switch (zig_ty) {2616 break :blk self.bss_section_index.?;
2619 // TODO: what if this is a function pointer?
2620 .Fn => break :blk self.text_section_index.?,
2621 else => {
2622 if (val.getVariable(mod)) |_| {
2623 break :blk self.data_section_index.?;
2624 }2617 }
2625 break :blk self.rodata_section_index.?;2618 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
2626 },2619 // intrusive check for all zeroes than this?
2627 }2620 const is_all_zeroes = for (code) |byte| {
2621 if (byte != 0) break false;
2622 } else true;
2623 if (is_all_zeroes) break :blk self.bss_section_index.?;
2624 break :blk self.data_section_index.?;
2625 }
2626 break :blk self.rodata_section_index.?;
2627 },
2628 };2628 };
2629 return shdr_index;2629 return shdr_index;
2630}2630}
...@@ -2649,7 +2649,10 @@ fn updateDeclCode(...@@ -2649,7 +2649,10 @@ fn updateDeclCode(
2649 const sym = self.symbol(sym_index);2649 const sym = self.symbol(sym_index);
2650 const esym = &zig_module.local_esyms.items[sym.esym_index];2650 const esym = &zig_module.local_esyms.items[sym.esym_index];
2651 const atom_ptr = sym.atom(self).?;2651 const atom_ptr = sym.atom(self).?;
2652 const shdr_index = sym.output_section_index;2652
2653 const shdr_index = self.getDeclShdrIndex(decl_index, code);
2654 sym.output_section_index = shdr_index;
2655 atom_ptr.output_section_index = shdr_index;
26532656
2654 sym.name_offset = try self.strtab.insert(gpa, decl_name);2657 sym.name_offset = try self.strtab.insert(gpa, decl_name);
2655 atom_ptr.alive = true;2658 atom_ptr.alive = true;
...@@ -2902,9 +2905,14 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -2902,9 +2905,14 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
2902 },2905 },
2903 };2906 };
29042907
2908 const output_section_index = switch (sym.kind) {
2909 .code => self.text_section_index.?,
2910 .const_data => self.rodata_section_index.?,
2911 };
2905 const local_sym = self.symbol(symbol_index);2912 const local_sym = self.symbol(symbol_index);
2906 const phdr_index = self.phdr_to_shdr_table.get(local_sym.output_section_index).?;2913 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
2907 local_sym.name_offset = name_str_index;2914 local_sym.name_offset = name_str_index;
2915 local_sym.output_section_index = output_section_index;
2908 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];2916 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
2909 local_esym.st_name = name_str_index;2917 local_esym.st_name = name_str_index;
2910 local_esym.st_info |= elf.STT_OBJECT;2918 local_esym.st_info |= elf.STT_OBJECT;
...@@ -2914,6 +2922,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -2914,6 +2922,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
2914 atom_ptr.name_offset = name_str_index;2922 atom_ptr.name_offset = name_str_index;
2915 atom_ptr.alignment = required_alignment;2923 atom_ptr.alignment = required_alignment;
2916 atom_ptr.size = code.len;2924 atom_ptr.size = code.len;
2925 atom_ptr.output_section_index = output_section_index;
29172926
2918 try atom_ptr.allocate(self);2927 try atom_ptr.allocate(self);
2919 errdefer self.freeDeclMetadata(symbol_index);2928 errdefer self.freeDeclMetadata(symbol_index);
...@@ -2932,7 +2941,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -2932,7 +2941,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
2932 try self.got.writeEntry(self, gop.index);2941 try self.got.writeEntry(self, gop.index);
29332942
2934 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;2943 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
2935 const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset;2944 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
2936 try self.base.file.?.pwriteAll(code, file_offset);2945 try self.base.file.?.pwriteAll(code, file_offset);
2937}2946}
29382947
...@@ -2960,7 +2969,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2960,7 +2969,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2960 const name = self.strtab.get(name_str_index).?;2969 const name = self.strtab.get(name_str_index).?;
29612970
2962 const zig_module = self.file(self.zig_module_index.?).?.zig_module;2971 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
2963 const sym_index = try zig_module.addAtom(self.rodata_section_index.?, self);2972 const sym_index = try zig_module.addAtom(self);
29642973
2965 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{2974 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{
2966 .none = {},2975 .none = {},
...@@ -2982,6 +2991,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2982,6 +2991,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2982 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;2991 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
2983 const local_sym = self.symbol(sym_index);2992 const local_sym = self.symbol(sym_index);
2984 local_sym.name_offset = name_str_index;2993 local_sym.name_offset = name_str_index;
2994 local_sym.output_section_index = self.rodata_section_index.?;
2985 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];2995 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
2986 local_esym.st_name = name_str_index;2996 local_esym.st_name = name_str_index;
2987 local_esym.st_info |= elf.STT_OBJECT;2997 local_esym.st_info |= elf.STT_OBJECT;
...@@ -2991,6 +3001,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2991,6 +3001,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2991 atom_ptr.name_offset = name_str_index;3001 atom_ptr.name_offset = name_str_index;
2992 atom_ptr.alignment = required_alignment;3002 atom_ptr.alignment = required_alignment;
2993 atom_ptr.size = code.len;3003 atom_ptr.size = code.len;
3004 atom_ptr.output_section_index = self.rodata_section_index.?;
29943005
2995 try atom_ptr.allocate(self);3006 try atom_ptr.allocate(self);
2996 errdefer self.freeDeclMetadata(sym_index);3007 errdefer self.freeDeclMetadata(sym_index);
...@@ -4008,6 +4019,54 @@ fn reportParseError(...@@ -4008,6 +4019,54 @@ fn reportParseError(
4008 });4019 });
4009}4020}
40104021
4022fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) {
4023 return .{ .data = self };
4024}
4025
4026fn formatShdrs(
4027 self: *Elf,
4028 comptime unused_fmt_string: []const u8,
4029 options: std.fmt.FormatOptions,
4030 writer: anytype,
4031) !void {
4032 _ = options;
4033 _ = unused_fmt_string;
4034 for (self.shdrs.items, 0..) |shdr, i| {
4035 try writer.print("shdr({d}) : phdr({?d}) : {s} : @{x} ({x}) : align({x}) : size({x})\n", .{
4036 i, self.phdr_to_shdr_table.get(@intCast(i)),
4037 self.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset,
4038 shdr.sh_addr, shdr.sh_addralign,
4039 shdr.sh_size,
4040 });
4041 }
4042}
4043
4044fn fmtPhdrs(self: *Elf) std.fmt.Formatter(formatPhdrs) {
4045 return .{ .data = self };
4046}
4047
4048fn formatPhdrs(
4049 self: *Elf,
4050 comptime unused_fmt_string: []const u8,
4051 options: std.fmt.FormatOptions,
4052 writer: anytype,
4053) !void {
4054 _ = options;
4055 _ = unused_fmt_string;
4056 for (self.phdrs.items, 0..) |phdr, i| {
4057 const write = phdr.p_flags & elf.PF_W != 0;
4058 const read = phdr.p_flags & elf.PF_R != 0;
4059 const exec = phdr.p_flags & elf.PF_X != 0;
4060 var flags: [3]u8 = [_]u8{'_'} ** 3;
4061 if (exec) flags[0] = 'X';
4062 if (write) flags[1] = 'W';
4063 if (read) flags[2] = 'R';
4064 try writer.print("phdr({d}) : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})\n", .{
4065 i, flags, phdr.p_offset, phdr.p_vaddr, phdr.p_align, phdr.p_filesz, phdr.p_memsz,
4066 });
4067 }
4068}
4069
4011fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {4070fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {
4012 return .{ .data = self };4071 return .{ .data = self };
4013}4072}
...@@ -4047,6 +4106,10 @@ fn fmtDumpState(...@@ -4047,6 +4106,10 @@ fn fmtDumpState(
4047 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});4106 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
4048 }4107 }
4049 try writer.print("{}\n", .{self.got.fmt(self)});4108 try writer.print("{}\n", .{self.got.fmt(self)});
4109 try writer.writeAll("Output shdrs\n");
4110 try writer.print("{}\n", .{self.fmtShdrs()});
4111 try writer.writeAll("Output phdrs\n");
4112 try writer.print("{}\n", .{self.fmtPhdrs()});
4050}4113}
40514114
4052/// Binary search4115/// Binary search
src/link/Elf/Atom.zig+10-5
...@@ -17,7 +17,7 @@ alignment: Alignment = .@"1",...@@ -17,7 +17,7 @@ alignment: Alignment = .@"1",
17input_section_index: Index = 0,17input_section_index: Index = 0,
1818
19/// Index of the output section.19/// Index of the output section.
20output_section_index: Index = 0,20output_section_index: u16 = 0,
2121
22/// Index of the input section containing this atom's relocs.22/// Index of the input section containing this atom's relocs.
23relocs_section_index: Index = 0,23relocs_section_index: Index = 0,
...@@ -53,6 +53,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {...@@ -53,6 +53,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {
53 return object.shdrs.items[self.input_section_index];53 return object.shdrs.items[self.input_section_index];
54}54}
5555
56pub fn outputShndx(self: Atom) ?u16 {
57 if (self.output_section_index == 0) return null;
58 return self.output_section_index;
59}
60
56pub fn codeInObject(self: Atom, elf_file: *Elf) error{Overflow}![]const u8 {61pub fn codeInObject(self: Atom, elf_file: *Elf) error{Overflow}![]const u8 {
57 const object = elf_file.file(self.file_index).?.object;62 const object = elf_file.file(self.file_index).?.object;
58 return object.shdrContents(self.input_section_index);63 return object.shdrContents(self.input_section_index);
...@@ -109,8 +114,8 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {...@@ -109,8 +114,8 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
109}114}
110115
111pub fn allocate(self: *Atom, elf_file: *Elf) !void {116pub fn allocate(self: *Atom, elf_file: *Elf) !void {
112 const shdr = &elf_file.shdrs.items[self.output_section_index];117 const shdr = &elf_file.shdrs.items[self.outputShndx().?];
113 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;118 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.outputShndx().?).?;
114 const free_list = &meta.free_list;119 const free_list = &meta.free_list;
115 const last_atom_index = &meta.last_atom_index;120 const last_atom_index = &meta.last_atom_index;
116 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);121 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
...@@ -179,7 +184,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -179,7 +184,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
179 true;184 true;
180 if (expand_section) {185 if (expand_section) {
181 const needed_size = (self.value + self.size) - shdr.sh_addr;186 const needed_size = (self.value + self.size) - shdr.sh_addr;
182 try elf_file.growAllocSection(self.output_section_index, needed_size);187 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
183 last_atom_index.* = self.atom_index;188 last_atom_index.* = self.atom_index;
184189
185 if (elf_file.dwarf) |_| {190 if (elf_file.dwarf) |_| {
...@@ -234,7 +239,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -234,7 +239,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
234239
235 const gpa = elf_file.base.allocator;240 const gpa = elf_file.base.allocator;
236 const zig_module = elf_file.file(self.file_index).?.zig_module;241 const zig_module = elf_file.file(self.file_index).?.zig_module;
237 const shndx = self.output_section_index;242 const shndx = self.outputShndx().?;
238 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;243 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
239 const free_list = &meta.free_list;244 const free_list = &meta.free_list;
240 const last_atom_index = &meta.last_atom_index;245 const last_atom_index = &meta.last_atom_index;
src/link/Elf/Object.zig+4-4
...@@ -272,9 +272,9 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void {...@@ -272,9 +272,9 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void {
272 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];272 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
273 sym_ptr.file_index = self.index;273 sym_ptr.file_index = self.index;
274 sym_ptr.output_section_index = if (sym_ptr.atom(elf_file)) |atom_ptr|274 sym_ptr.output_section_index = if (sym_ptr.atom(elf_file)) |atom_ptr|
275 atom_ptr.output_section_index275 atom_ptr.outputShndx().?
276 else276 else
277 0;277 elf.SHN_UNDEF;
278 }278 }
279279
280 for (self.symtab[first_global..]) |sym| {280 for (self.symtab[first_global..]) |sym| {
...@@ -440,9 +440,9 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -440,9 +440,9 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
440 else => self.atoms.items[esym.st_shndx],440 else => self.atoms.items[esym.st_shndx],
441 };441 };
442 const output_section_index = if (elf_file.atom(atom_index)) |atom|442 const output_section_index = if (elf_file.atom(atom_index)) |atom|
443 atom.output_section_index443 atom.outputShndx().?
444 else444 else
445 0;445 elf.SHN_UNDEF;
446 global.value = esym.st_value;446 global.value = esym.st_value;
447 global.atom_index = atom_index;447 global.atom_index = atom_index;
448 global.esym_index = esym_index;448 global.esym_index = esym_index;
src/link/Elf/Symbol.zig+9-4
...@@ -33,10 +33,15 @@ extra_index: u32 = 0,...@@ -33,10 +33,15 @@ extra_index: u32 = 0,
33pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {33pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
34 const file_ptr = symbol.file(elf_file).?;34 const file_ptr = symbol.file(elf_file).?;
35 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;35 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
36 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and36 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and
37 file_ptr != .linker_defined;37 file_ptr != .linker_defined;
38}38}
3939
40pub fn outputShndx(symbol: Symbol) ?u16 {
41 if (symbol.output_section_index == 0) return null;
42 return symbol.output_section_index;
43}
44
40pub fn isLocal(symbol: Symbol) bool {45pub fn isLocal(symbol: Symbol) bool {
41 return !(symbol.flags.import or symbol.flags.@"export");46 return !(symbol.flags.import or symbol.flags.@"export");
42}47}
...@@ -183,7 +188,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -183,7 +188,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
183 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;188 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
184 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)189 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
185 break :blk elf.SHN_ABS;190 break :blk elf.SHN_ABS;
186 break :blk symbol.output_section_index;191 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
187 };192 };
188 const st_value = blk: {193 const st_value = blk: {
189 // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);194 // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);
...@@ -276,8 +281,8 @@ fn format2(...@@ -276,8 +281,8 @@ fn format2(
276 } else {281 } else {
277 try writer.writeAll(" : absolute");282 try writer.writeAll(" : absolute");
278 }283 }
279 } else if (symbol.output_section_index != 0) {284 } else if (symbol.outputShndx()) |shndx| {
280 try writer.print(" : sect({d})", .{symbol.output_section_index});285 try writer.print(" : sect({d})", .{shndx});
281 }286 }
282 if (symbol.atom(ctx.elf_file)) |atom_ptr| {287 if (symbol.atom(ctx.elf_file)) |atom_ptr| {
283 try writer.print(" : atom({d})", .{atom_ptr.atom_index});288 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
src/link/Elf/ZigModule.zig+3-5
...@@ -49,21 +49,19 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {...@@ -49,21 +49,19 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
49 return index | 0x10000000;49 return index | 0x10000000;
50}50}
5151
52pub fn addAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {52pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
53 const gpa = elf_file.base.allocator;53 const gpa = elf_file.base.allocator;
5454
55 const atom_index = try elf_file.addAtom();55 const atom_index = try elf_file.addAtom();
56 try self.atoms.putNoClobber(gpa, atom_index, {});56 try self.atoms.putNoClobber(gpa, atom_index, {});
57 const atom_ptr = elf_file.atom(atom_index).?;57 const atom_ptr = elf_file.atom(atom_index).?;
58 atom_ptr.file_index = self.index;58 atom_ptr.file_index = self.index;
59 atom_ptr.output_section_index = output_section_index;
6059
61 const symbol_index = try elf_file.addSymbol();60 const symbol_index = try elf_file.addSymbol();
62 try self.local_symbols.append(gpa, symbol_index);61 try self.local_symbols.append(gpa, symbol_index);
63 const symbol_ptr = elf_file.symbol(symbol_index);62 const symbol_ptr = elf_file.symbol(symbol_index);
64 symbol_ptr.file_index = self.index;63 symbol_ptr.file_index = self.index;
65 symbol_ptr.atom_index = atom_index;64 symbol_ptr.atom_index = atom_index;
66 symbol_ptr.output_section_index = output_section_index;
6765
68 const esym_index = try self.addLocalEsym(gpa);66 const esym_index = try self.addLocalEsym(gpa);
69 const esym = &self.local_esyms.items[esym_index];67 const esym = &self.local_esyms.items[esym_index];
...@@ -98,9 +96,9 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {...@@ -98,9 +96,9 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
98 else => esym.st_shndx,96 else => esym.st_shndx,
99 };97 };
100 const output_section_index = if (elf_file.atom(atom_index)) |atom|98 const output_section_index = if (elf_file.atom(atom_index)) |atom|
101 atom.output_section_index99 atom.outputShndx().?
102 else100 else
103 0;101 elf.SHN_UNDEF;
104 global.value = esym.st_value;102 global.value = esym.st_value;
105 global.atom_index = atom_index;103 global.atom_index = atom_index;
106 global.esym_index = esym_index;104 global.esym_index = esym_index;