From b44dd599ad4a0f8a6684acd6e3c5a02f3c7b8f04 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 27 Aug 2024 12:53:05 +0200 Subject: [PATCH 01/35] elf: split Atom.allocate into Atom-independent parts --- src/link/Elf.zig | 77 +++++++++++++++++++++ src/link/Elf/Atom.zig | 134 ------------------------------------- src/link/Elf/ZigObject.zig | 66 ++++++++++++++++-- 3 files changed, 136 insertions(+), 141 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 194c1b8ad2..4957811e7a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -675,6 +675,83 @@ pub fn markDirty(self: *Elf, shdr_index: u32) void { } } +const AllocateChunkResult = struct { + value: u64, + placement: Ref, +}; + +pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignment) !AllocateChunkResult { + const slice = self.sections.slice(); + const shdr = &slice.items(.shdr)[shndx]; + const free_list = &slice.items(.free_list)[shndx]; + const last_atom_ref = &slice.items(.last_atom)[shndx]; + const new_atom_ideal_capacity = padToIdeal(size); + + // First we look for an appropriately sized free list node. + // The list is unordered. We'll just take the first thing that works. + const res: AllocateChunkResult = blk: { + var i: usize = if (self.base.child_pid == null) 0 else free_list.items.len; + while (i < free_list.items.len) { + const big_atom_ref = free_list.items[i]; + const big_atom = self.atom(big_atom_ref).?; + // We now have a pointer to a live atom that has too much capacity. + // Is it enough that we could fit this new atom? + const cap = big_atom.capacity(self); + const ideal_capacity = padToIdeal(cap); + const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; + const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; + const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; + const new_start_vaddr = alignment.backward(new_start_vaddr_unaligned); + if (new_start_vaddr < ideal_capacity_end_vaddr) { + // Additional bookkeeping here to notice if this free list node + // should be deleted because the block that it points to has grown to take up + // more of the extra capacity. + if (!big_atom.freeListEligible(self)) { + _ = free_list.swapRemove(i); + } else { + i += 1; + } + continue; + } + // At this point we know that we will place the new block here. But the + // remaining question is whether there is still yet enough capacity left + // over for there to still be a free list node. + const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; + const keep_free_list_node = remaining_capacity >= min_text_capacity; + + if (!keep_free_list_node) { + _ = free_list.swapRemove(i); + } + break :blk .{ .value = new_start_vaddr, .placement = big_atom_ref }; + } else if (self.atom(last_atom_ref.*)) |last_atom| { + const ideal_capacity = padToIdeal(last_atom.size); + const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity; + const new_start_vaddr = alignment.forward(ideal_capacity_end_vaddr); + break :blk .{ .value = new_start_vaddr, .placement = last_atom.ref() }; + } else { + break :blk .{ .value = 0, .placement = .{} }; + } + }; + + log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{ + size, + alignment.toByteUnits().?, + shdr.sh_addr + res.value, + shdr.sh_offset + res.value, + }); + + const expand_section = if (self.atom(res.placement)) |placement_atom| + placement_atom.nextAtom(self) == null + else + true; + if (expand_section) { + const needed_size = res.value + size; + try self.growAllocSection(shndx, needed_size); + } + + return res; +} + pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; if (use_lld) { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index ef2301f1cd..3d1fe04fb5 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -123,140 +123,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { return surplus >= Elf.min_text_capacity; } -pub fn allocate(self: *Atom, elf_file: *Elf) !void { - const slice = elf_file.sections.slice(); - const shdr = &slice.items(.shdr)[self.output_section_index]; - const free_list = &slice.items(.free_list)[self.output_section_index]; - const last_atom_ref = &slice.items(.last_atom)[self.output_section_index]; - const new_atom_ideal_capacity = Elf.padToIdeal(self.size); - - // We use these to indicate our intention to update metadata, placing the new atom, - // and possibly removing a free list node. - // It would be simpler to do it inside the for loop below, but that would cause a - // problem if an error was returned later in the function. So this action - // is actually carried out at the end of the function, when errors are no longer possible. - var atom_placement: ?Elf.Ref = null; - var free_list_removal: ?usize = null; - - // First we look for an appropriately sized free list node. - // The list is unordered. We'll just take the first thing that works. - self.value = blk: { - var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len; - while (i < free_list.items.len) { - const big_atom_ref = free_list.items[i]; - const big_atom = elf_file.atom(big_atom_ref).?; - // We now have a pointer to a live atom that has too much capacity. - // Is it enough that we could fit this new atom? - const cap = big_atom.capacity(elf_file); - const ideal_capacity = Elf.padToIdeal(cap); - const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; - const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; - const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; - const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); - if (new_start_vaddr < ideal_capacity_end_vaddr) { - // Additional bookkeeping here to notice if this free list node - // should be deleted because the block that it points to has grown to take up - // more of the extra capacity. - if (!big_atom.freeListEligible(elf_file)) { - _ = free_list.swapRemove(i); - } else { - i += 1; - } - continue; - } - // At this point we know that we will place the new block here. But the - // remaining question is whether there is still yet enough capacity left - // over for there to still be a free list node. - const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; - const keep_free_list_node = remaining_capacity >= Elf.min_text_capacity; - - // Set up the metadata to be updated, after errors are no longer possible. - atom_placement = big_atom_ref; - if (!keep_free_list_node) { - free_list_removal = i; - } - break :blk @intCast(new_start_vaddr); - } else if (elf_file.atom(last_atom_ref.*)) |last_atom| { - const ideal_capacity = Elf.padToIdeal(last_atom.size); - const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity; - const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); - // Set up the metadata to be updated, after errors are no longer possible. - atom_placement = last_atom.ref(); - break :blk @intCast(new_start_vaddr); - } else { - break :blk 0; - } - }; - - log.debug("allocated atom({}) : '{s}' at 0x{x} to 0x{x}", .{ - self.ref(), - self.name(elf_file), - self.address(elf_file), - self.address(elf_file) + @as(i64, @intCast(self.size)), - }); - - const expand_section = if (atom_placement) |placement_ref| - elf_file.atom(placement_ref).?.nextAtom(elf_file) == null - else - true; - if (expand_section) { - const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size))); - try elf_file.growAllocSection(self.output_section_index, needed_size); - last_atom_ref.* = self.ref(); - - switch (self.file(elf_file).?) { - .zig_object => |zo| if (zo.dwarf) |_| { - // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address - // range of the compilation unit. When we expand the text section, this range changes, - // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. - zo.debug_info_section_dirty = true; - // This becomes dirty for the same reason. We could potentially make this more - // fine-grained with the addition of support for more compilation units. It is planned to - // model each package as a different compilation unit. - zo.debug_aranges_section_dirty = true; - zo.debug_rnglists_section_dirty = true; - }, - else => {}, - } - } - shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?); - - // This function can also reallocate an atom. - // In this case we need to "unplug" it from its previous location before - // plugging it in to its new location. - if (self.prevAtom(elf_file)) |prev| { - prev.next_atom_ref = self.next_atom_ref; - } - if (self.nextAtom(elf_file)) |next| { - next.prev_atom_ref = self.prev_atom_ref; - } - - if (atom_placement) |big_atom_ref| { - const big_atom = elf_file.atom(big_atom_ref).?; - self.prev_atom_ref = big_atom_ref; - self.next_atom_ref = big_atom.next_atom_ref; - big_atom.next_atom_ref = self.ref(); - } else { - self.prev_atom_ref = .{ .index = 0, .file = 0 }; - self.next_atom_ref = .{ .index = 0, .file = 0 }; - } - if (free_list_removal) |i| { - _ = free_list.swapRemove(i); - } - - self.alive = true; -} - -pub fn shrink(self: *Atom, elf_file: *Elf) void { - _ = self; - _ = elf_file; -} - -pub fn grow(self: *Atom, elf_file: *Elf) !void { - if (!self.alignment.check(@intCast(self.value)) or self.size > self.capacity(elf_file)) - try self.allocate(elf_file); -} - pub fn free(self: *Atom, elf_file: *Elf) void { log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) }); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 549657800c..ce839a512b 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1362,19 +1362,18 @@ fn updateNavCode( const capacity = atom_ptr.capacity(elf_file); const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value)); if (need_realloc) { - try atom_ptr.grow(elf_file); + try self.growAtom(atom_ptr, elf_file); log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value }); if (old_vaddr != atom_ptr.value) { sym.value = 0; esym.st_value = 0; } } else if (code.len < old_size) { - atom_ptr.shrink(elf_file); + // TODO shrink section size } } else { - try atom_ptr.allocate(elf_file); + try self.allocateAtom(atom_ptr, elf_file); errdefer self.freeNavMetadata(elf_file, sym_index); - sym.value = 0; esym.st_value = 0; } @@ -1739,7 +1738,7 @@ fn updateLazySymbol( atom_ptr.size = code.len; atom_ptr.output_section_index = output_section_index; - try atom_ptr.allocate(elf_file); + try self.allocateAtom(atom_ptr, elf_file); errdefer self.freeNavMetadata(elf_file, symbol_index); local_sym.value = 0; @@ -1797,8 +1796,7 @@ fn lowerConst( atom_ptr.size = code.len; atom_ptr.output_section_index = output_section_index; - try atom_ptr.allocate(elf_file); - // TODO rename and re-audit this method + try self.allocateAtom(atom_ptr, elf_file); errdefer self.freeNavMetadata(elf_file, sym_index); const shdr = elf_file.sections.items(.shdr)[output_section_index]; @@ -1998,6 +1996,60 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { } } +fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { + const alloc_res = try elf_file.allocateChunk(atom_ptr.output_section_index, atom_ptr.size, atom_ptr.alignment); + atom_ptr.value = @intCast(alloc_res.value); + + const slice = elf_file.sections.slice(); + const shdr = &slice.items(.shdr)[atom_ptr.output_section_index]; + const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index]; + + const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom| + placement_atom.nextAtom(elf_file) == null + else + true; + if (expand_section) { + last_atom_ref.* = atom_ptr.ref(); + if (self.dwarf) |_| { + // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address + // range of the compilation unit. When we expand the text section, this range changes, + // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. + self.debug_info_section_dirty = true; + // This becomes dirty for the same reason. We could potentially make this more + // fine-grained with the addition of support for more compilation units. It is planned to + // model each package as a different compilation unit. + self.debug_aranges_section_dirty = true; + self.debug_rnglists_section_dirty = true; + } + } + shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?); + + // This function can also reallocate an atom. + // In this case we need to "unplug" it from its previous location before + // plugging it in to its new location. + if (atom_ptr.prevAtom(elf_file)) |prev| { + prev.next_atom_ref = atom_ptr.next_atom_ref; + } + if (atom_ptr.nextAtom(elf_file)) |next| { + next.prev_atom_ref = atom_ptr.prev_atom_ref; + } + + if (elf_file.atom(alloc_res.placement)) |big_atom| { + atom_ptr.prev_atom_ref = alloc_res.placement; + atom_ptr.next_atom_ref = big_atom.next_atom_ref; + big_atom.next_atom_ref = atom_ptr.ref(); + } else { + atom_ptr.prev_atom_ref = .{ .index = 0, .file = 0 }; + atom_ptr.next_atom_ref = .{ .index = 0, .file = 0 }; + } +} + +fn growAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { + if (!atom_ptr.alignment.check(@intCast(atom_ptr.value)) or atom_ptr.size > atom_ptr.capacity(elf_file)) { + try self.allocateAtom(atom_ptr, elf_file); + } +} + pub fn asFile(self: *ZigObject) File { return .{ .zig_object = self }; } From d32af9ea2ade7c447ac8b882076dba337a10dc51 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 27 Aug 2024 15:22:33 +0200 Subject: [PATCH 02/35] elf: move initOutputSection into Elf from Object --- src/link/Elf.zig | 53 ++++++++++++++++++++++++++++ src/link/Elf/Object.zig | 76 +++++++++++------------------------------ 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 4957811e7a..1ef5a562a8 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1827,6 +1827,59 @@ fn scanRelocs(self: *Elf) !void { } } +pub fn initOutputSection(self: *Elf, args: struct { + name: [:0]const u8, + flags: u64, + type: u32, +}) error{OutOfMemory}!u32 { + const name = blk: { + if (self.base.isRelocatable()) break :blk args.name; + if (args.flags & elf.SHF_MERGE != 0) break :blk args.name; + const name_prefixes: []const [:0]const u8 = &.{ + ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", + ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", + ".dtors", ".gnu.warning", + }; + inline for (name_prefixes) |prefix| { + if (std.mem.eql(u8, args.name, prefix) or std.mem.startsWith(u8, args.name, prefix ++ ".")) { + break :blk prefix; + } + } + break :blk args.name; + }; + const @"type" = tt: { + if (self.getTarget().cpu.arch == .x86_64 and + args.type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS; + switch (args.type) { + elf.SHT_NULL => unreachable, + elf.SHT_PROGBITS => { + if (std.mem.eql(u8, args.name, ".init_array") or std.mem.startsWith(u8, args.name, ".init_array.")) + break :tt elf.SHT_INIT_ARRAY; + if (std.mem.eql(u8, args.name, ".fini_array") or std.mem.startsWith(u8, args.name, ".fini_array.")) + break :tt elf.SHT_FINI_ARRAY; + break :tt args.type; + }, + else => break :tt args.type, + } + }; + const flags = blk: { + var flags = args.flags; + if (!self.base.isRelocatable()) { + flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); + } + break :blk switch (@"type") { + elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, + else => flags, + }; + }; + const out_shndx = self.sectionByName(name) orelse try self.addSection(.{ + .type = @"type", + .flags = flags, + .name = try self.insertShString(name), + }); + return out_shndx; +} + fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { dev.check(.lld_linker); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 40d09c8ec4..c4443bb67e 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -311,58 +311,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: }; } -fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 { - const name = blk: { - const name = self.getString(shdr.sh_name); - if (elf_file.base.isRelocatable()) break :blk name; - if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; - const sh_name_prefixes: []const [:0]const u8 = &.{ - ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", - ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", - ".dtors", ".gnu.warning", - }; - inline for (sh_name_prefixes) |prefix| { - if (std.mem.eql(u8, name, prefix) or std.mem.startsWith(u8, name, prefix ++ ".")) { - break :blk prefix; - } - } - break :blk name; - }; - const @"type" = tt: { - if (elf_file.getTarget().cpu.arch == .x86_64 and - shdr.sh_type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS; - - const @"type" = switch (shdr.sh_type) { - elf.SHT_NULL => unreachable, - elf.SHT_PROGBITS => blk: { - if (std.mem.eql(u8, name, ".init_array") or std.mem.startsWith(u8, name, ".init_array.")) - break :blk elf.SHT_INIT_ARRAY; - if (std.mem.eql(u8, name, ".fini_array") or std.mem.startsWith(u8, name, ".fini_array.")) - break :blk elf.SHT_FINI_ARRAY; - break :blk shdr.sh_type; - }, - else => shdr.sh_type, - }; - break :tt @"type"; - }; - const flags = blk: { - var flags = shdr.sh_flags; - if (!elf_file.base.isRelocatable()) { - flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); - } - break :blk switch (@"type") { - elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, - else => flags, - }; - }; - const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{ - .type = @"type", - .flags = flags, - .name = try elf_file.insertShString(name), - }); - return out_shndx; -} - fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { const comp = elf_file.base.comp; const shdr = self.shdrs.items[index]; @@ -985,7 +933,11 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; const shdr = atom_ptr.inputShdr(elf_file); - _ = try self.initOutputSection(elf_file, shdr); + _ = try elf_file.initOutputSection(.{ + .name = self.getString(shdr.sh_name), + .flags = shdr.sh_flags, + .type = shdr.sh_type, + }); } } @@ -994,7 +946,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; const shdr = atom_ptr.inputShdr(elf_file); - atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable; + atom_ptr.output_section_index = elf_file.initOutputSection(.{ + .name = self.getString(shdr.sh_name), + .flags = shdr.sh_flags, + .type = shdr.sh_type, + }) catch unreachable; const comp = elf_file.base.comp; const gpa = comp.gpa; @@ -1009,7 +965,11 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void { if (!atom_ptr.alive) continue; const shndx = atom_ptr.relocsShndx() orelse continue; const shdr = self.shdrs.items[shndx]; - const out_shndx = try self.initOutputSection(elf_file, shdr); + const out_shndx = try elf_file.initOutputSection(.{ + .name = self.getString(shdr.sh_name), + .flags = shdr.sh_flags, + .type = shdr.sh_type, + }); const out_shdr = &elf_file.sections.items(.shdr)[out_shndx]; out_shdr.sh_type = elf.SHT_RELA; out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela); @@ -1025,7 +985,11 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void { const shndx = blk: { const shndx = atom_ptr.relocsShndx() orelse continue; const shdr = self.shdrs.items[shndx]; - break :blk self.initOutputSection(elf_file, shdr) catch unreachable; + break :blk elf_file.initOutputSection(.{ + .name = self.getString(shdr.sh_name), + .flags = shdr.sh_flags, + .type = shdr.sh_type, + }) catch unreachable; }; const slice = elf_file.sections.slice(); const shdr = &slice.items(.shdr)[shndx]; From 8f1ce3c85b6463206147119dd56ba415f6e4d28e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 27 Aug 2024 15:34:13 +0200 Subject: [PATCH 03/35] elf: shuffle some stages to make it clear what needs what --- src/link/Elf.zig | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1ef5a562a8..bfbc34503f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1049,14 +1049,16 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod try self.initSyntheticSections(); try self.initSpecialPhdrs(); try self.sortShdrs(); - for (self.objects.items) |index| { - try self.file(index).?.object.addAtomsToOutputSections(self); - } - try self.sortInitFini(); + try self.setDynamicSection(rpath_table.keys()); self.sortDynamicSymtab(); try self.setHashSections(); try self.setVersionSymtab(); + + for (self.objects.items) |index| { + try self.file(index).?.object.addAtomsToOutputSections(self); + } + try self.sortInitFini(); try self.updateMergeSectionSizes(); try self.updateSectionSizes(); From 37a1f0e7f2586b1fd3c88c3483f0c9f731f41a30 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 28 Aug 2024 06:57:55 +0200 Subject: [PATCH 04/35] elf: allocate .bss in ZigObject similarly to .eh_frame --- src/link/Elf.zig | 16 +++--- src/link/Elf/ZigObject.zig | 114 +++++++++++++++++-------------------- 2 files changed, 61 insertions(+), 69 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index bfbc34503f..5757e40ab8 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -61,8 +61,6 @@ phdr_zig_load_re_index: ?u16 = null, phdr_zig_load_ro_index: ?u16 = null, /// The index into the program headers of a PT_LOAD program header with Write flag phdr_zig_load_rw_index: ?u16 = null, -/// The index into the program headers of a PT_LOAD program header with zerofill data. -phdr_zig_load_zerofill_index: ?u16 = null, /// Special program headers /// PT_PHDR @@ -129,7 +127,6 @@ comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, zig_text_section_index: ?u32 = null, zig_data_rel_ro_section_index: ?u32 = null, zig_data_section_index: ?u32 = null, -zig_bss_section_index: ?u32 = null, debug_info_section_index: ?u32 = null, debug_abbrev_section_index: ?u32 = null, @@ -3367,7 +3364,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { for (&[_]*?u16{ &self.phdr_zig_load_re_index, &self.phdr_zig_load_ro_index, - &self.phdr_zig_load_zerofill_index, &self.phdr_table_index, &self.phdr_table_load_index, &self.phdr_interp_index, @@ -3496,7 +3492,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { &self.zig_text_section_index, &self.zig_data_rel_ro_section_index, &self.zig_data_section_index, - &self.zig_bss_section_index, &self.debug_info_section_index, &self.debug_abbrev_section_index, &self.debug_str_section_index, @@ -3591,9 +3586,17 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { fn updateSectionSizes(self: *Elf) !void { const slice = self.sections.slice(); - for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { + for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { if (atom_list.items.len == 0) continue; if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; + if (self.zigObjectPtr()) |zo| { + if (zo.bss_index) |sym_index| { + const atom_ptr = zo.symbol(sym_index).atom(self).?; + if (shndx == atom_ptr.output_section_index) { + shdr.sh_size = atom_ptr.size; + } + } + } for (atom_list.items) |ref| { const atom_ptr = self.atom(ref) orelse continue; if (!atom_ptr.alive) continue; @@ -4804,7 +4807,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool { self.zig_text_section_index, self.zig_data_rel_ro_section_index, self.zig_data_section_index, - self.zig_bss_section_index, }) |index| { if (index == shndx) return true; } diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index ce839a512b..594dd5f640 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -60,6 +60,7 @@ debug_line_str_index: ?Symbol.Index = null, debug_loclists_index: ?Symbol.Index = null, debug_rnglists_index: ?Symbol.Index = null, eh_frame_index: ?Symbol.Index = null, +bss_index: ?Symbol.Index = null, pub const global_symbol_bit: u32 = 0x80000000; pub const symbol_mask: u32 = 0x7fffffff; @@ -149,17 +150,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .flags = elf.PF_R | elf.PF_W, }); } - - if (elf_file.phdr_zig_load_zerofill_index == null) { - const alignment = elf_file.page_size; - elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{ - .type = elf.PT_LOAD, - .addr = if (ptr_size >= 4) 0x14000000 else 0xf000, - .memsz = 1024, - .@"align" = alignment, - .flags = elf.PF_R | elf.PF_W, - }); - } } if (elf_file.zig_text_section_index == null) { @@ -225,51 +215,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { } } - if (elf_file.zig_bss_section_index == null) { - elf_file.zig_bss_section_index = try elf_file.addSection(.{ - .name = try elf_file.insertShString(".bss.zig"), - .type = elf.SHT_NOBITS, - .addralign = ptr_size, - .flags = elf.SHF_ALLOC | elf.SHF_WRITE, - .offset = 0, - }); - const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_bss_section_index.?]; - const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_bss_section_index.?]; - if (elf_file.base.isRelocatable()) { - shdr.sh_size = 1024; - } else { - phndx.* = elf_file.phdr_zig_load_zerofill_index.?; - const phdr = elf_file.phdrs.items[phndx.*.?]; - shdr.sh_addr = phdr.p_vaddr; - shdr.sh_size = phdr.p_memsz; - } - } - switch (comp.config.debug_format) { .strip => {}, .dwarf => |v| { var dwarf = Dwarf.init(&elf_file.base, v); - const addSectionSymbol = struct { - fn addSectionSymbol( - zig_object: *ZigObject, - alloc: Allocator, - name: [:0]const u8, - alignment: Atom.Alignment, - shndx: u32, - ) !Symbol.Index { - const name_off = try zig_object.addString(alloc, name); - const index = try zig_object.newSymbolWithAtom(alloc, name_off); - const sym = zig_object.symbol(index); - const esym = &zig_object.symtab.items(.elf_sym)[sym.esym_index]; - esym.st_info |= elf.STT_SECTION; - const atom_ptr = zig_object.atom(sym.ref.index).?; - atom_ptr.alignment = alignment; - atom_ptr.output_section_index = shndx; - return index; - } - }.addSectionSymbol; - if (elf_file.debug_str_section_index == null) { elf_file.debug_str_section_index = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_str"), @@ -279,7 +229,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_str_section_dirty = true; - self.debug_str_index = try addSectionSymbol(self, gpa, ".debug_str", .@"1", elf_file.debug_str_section_index.?); + self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", elf_file.debug_str_section_index.?); } if (elf_file.debug_info_section_index == null) { @@ -289,7 +239,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_info_section_dirty = true; - self.debug_info_index = try addSectionSymbol(self, gpa, ".debug_info", .@"1", elf_file.debug_info_section_index.?); + self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", elf_file.debug_info_section_index.?); } if (elf_file.debug_abbrev_section_index == null) { @@ -299,7 +249,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_abbrev_section_dirty = true; - self.debug_abbrev_index = try addSectionSymbol(self, gpa, ".debug_abbrev", .@"1", elf_file.debug_abbrev_section_index.?); + self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", elf_file.debug_abbrev_section_index.?); } if (elf_file.debug_aranges_section_index == null) { @@ -309,7 +259,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 16, }); self.debug_aranges_section_dirty = true; - self.debug_aranges_index = try addSectionSymbol(self, gpa, ".debug_aranges", .@"16", elf_file.debug_aranges_section_index.?); + self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", elf_file.debug_aranges_section_index.?); } if (elf_file.debug_line_section_index == null) { @@ -319,7 +269,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_line_section_dirty = true; - self.debug_line_index = try addSectionSymbol(self, gpa, ".debug_line", .@"1", elf_file.debug_line_section_index.?); + self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", elf_file.debug_line_section_index.?); } if (elf_file.debug_line_str_section_index == null) { @@ -331,7 +281,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_line_str_section_dirty = true; - self.debug_line_str_index = try addSectionSymbol(self, gpa, ".debug_line_str", .@"1", elf_file.debug_line_str_section_index.?); + self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", elf_file.debug_line_str_section_index.?); } if (elf_file.debug_loclists_section_index == null) { @@ -341,7 +291,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_loclists_section_dirty = true; - self.debug_loclists_index = try addSectionSymbol(self, gpa, ".debug_loclists", .@"1", elf_file.debug_loclists_section_index.?); + self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", elf_file.debug_loclists_section_index.?); } if (elf_file.debug_rnglists_section_index == null) { @@ -351,7 +301,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_rnglists_section_dirty = true; - self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?); + self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?); } if (elf_file.eh_frame_section_index == null) { @@ -365,7 +315,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = ptr_size, }); self.eh_frame_section_dirty = true; - self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?); + self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?); } try dwarf.initMetadata(); @@ -1270,6 +1220,24 @@ pub fn getOrCreateMetadataForNav( return gop.value_ptr.symbol_index; } +fn addSectionSymbol( + self: *ZigObject, + allocator: Allocator, + name: [:0]const u8, + alignment: Atom.Alignment, + shndx: u32, +) !Symbol.Index { + const name_off = try self.addString(allocator, name); + const index = try self.newSymbolWithAtom(allocator, name_off); + const sym = self.symbol(index); + const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; + esym.st_info |= elf.STT_SECTION; + const atom_ptr = self.atom(sym.ref.index).?; + atom_ptr.alignment = alignment; + atom_ptr.output_section_index = shndx; + return index; +} + fn getNavShdrIndex( self: *ZigObject, elf_file: *Elf, @@ -1309,12 +1277,34 @@ fn getNavShdrIndex( if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu)) return switch (zcu.navFileScope(nav_index).mod.optimize_mode) { .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, - .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?, + .ReleaseFast, .ReleaseSmall => { + if (self.bss_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .type = elf.SHT_NOBITS, + .flags = elf.SHF_ALLOC | elf.SHF_WRITE, + .name = try elf_file.insertShString(".bss"), + .addralign = 1, + }); + self.bss_index = try self.addSectionSymbol(elf_file.base.comp.gpa, ".bss", .@"1", osec); + return osec; + }, }; const is_bss = !has_relocs and for (code) |byte| { if (byte != 0) break false; } else true; - if (is_bss) return elf_file.zig_bss_section_index.?; + if (is_bss) { + if (self.bss_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .type = elf.SHT_NOBITS, + .flags = elf.SHF_ALLOC | elf.SHF_WRITE, + .name = try elf_file.insertShString(".bss"), + .addralign = 1, + }); + self.bss_index = try self.addSectionSymbol(elf_file.base.comp.gpa, ".bss", .@"1", osec); + return osec; + } return elf_file.zig_data_section_index.?; } From 0b92404ddf71c72664d2d4dd252e211a9678492d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 07:30:36 +0200 Subject: [PATCH 05/35] elf: allocate .data in ZigObject similarly to .eh_frame --- src/link/Elf.zig | 52 ++++++++++++++---------- src/link/Elf/ZigObject.zig | 81 +++++++++++++++++++------------------- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 5757e40ab8..ae6933fdf7 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -59,8 +59,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, phdr_zig_load_re_index: ?u16 = null, /// The index into the program headers of a PT_LOAD program header with Read flag phdr_zig_load_ro_index: ?u16 = null, -/// The index into the program headers of a PT_LOAD program header with Write flag -phdr_zig_load_rw_index: ?u16 = null, /// Special program headers /// PT_PHDR @@ -126,7 +124,6 @@ comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, /// .rela.* sections are only used when emitting a relocatable object file. zig_text_section_index: ?u32 = null, zig_data_rel_ro_section_index: ?u32 = null, -zig_data_section_index: ?u32 = null, debug_info_section_index: ?u32 = null, debug_abbrev_section_index: ?u32 = null, @@ -3491,7 +3488,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { &self.verneed_section_index, &self.zig_text_section_index, &self.zig_data_rel_ro_section_index, - &self.zig_data_section_index, &self.debug_info_section_index, &self.debug_abbrev_section_index, &self.debug_str_section_index, @@ -3589,12 +3585,16 @@ fn updateSectionSizes(self: *Elf) !void { for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { if (atom_list.items.len == 0) continue; if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; - if (self.zigObjectPtr()) |zo| { - if (zo.bss_index) |sym_index| { - const atom_ptr = zo.symbol(sym_index).atom(self).?; - if (shndx == atom_ptr.output_section_index) { - shdr.sh_size = atom_ptr.size; - } + if (self.zigObjectPtr()) |zo| blk: { + const sym_index = for ([_]?Symbol.Index{ + zo.data_index, + zo.bss_index, + }) |maybe_idx| { + if (maybe_idx) |idx| break idx; + } else break :blk; + const atom_ptr = zo.symbol(sym_index).atom(self).?; + if (shndx == atom_ptr.output_section_index) { + shdr.sh_size = atom_ptr.size; } } for (atom_list.items) |ref| { @@ -3929,10 +3929,16 @@ pub fn allocateAllocSections(self: *Elf) !void { } new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset); - if (shndx == self.eh_frame_section_index) eh_frame: { - const zo = self.zigObjectPtr() orelse break :eh_frame; - const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame); - const existing_size = sym.atom(self).?.size; + if (self.zigObjectPtr()) |zo| blk: { + const existing_size = for ([_]?Symbol.Index{ + zo.data_index, + zo.eh_frame_index, + }) |maybe_sym_index| { + const sect_sym_index = maybe_sym_index orelse continue; + const sect_atom_ptr = zo.symbol(sect_sym_index).atom(self).?; + if (sect_atom_ptr.output_section_index != shndx) continue; + break sect_atom_ptr.size; + } else break :blk; log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getShString(shdr.sh_name), shdr.sh_offset, @@ -4096,10 +4102,17 @@ fn writeAtoms(self: *Elf) !void { if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size; } break :base_offset 0; - } else if (@as(u32, @intCast(shndx)) == self.eh_frame_section_index) base_offset: { - const zo = self.zigObjectPtr() orelse break :base_offset 0; - const sym = zo.symbol(zo.eh_frame_index orelse break :base_offset 0); - break :base_offset sym.atom(self).?.size; + } else if (self.zigObjectPtr()) |zo| base_offset: { + const sym_index = for ([_]?Symbol.Index{ + zo.data_index, + zo.eh_frame_index, + }) |maybe_idx| { + if (maybe_idx) |idx| break idx; + } else break :base_offset 0; + const sym = zo.symbol(sym_index); + const atom_ptr = sym.atom(self).?; + if (atom_ptr.output_section_index == @as(u32, @intCast(shndx))) break :base_offset atom_ptr.size; + break :base_offset 0; } else 0; const sh_offset = shdr.sh_offset + base_offset; const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; @@ -4806,7 +4819,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool { inline for (&[_]?u32{ self.zig_text_section_index, self.zig_data_rel_ro_section_index, - self.zig_data_section_index, }) |index| { if (index == shndx) return true; } @@ -5507,7 +5519,7 @@ fn requiresThunks(self: Elf) bool { /// so that we reserve enough space for the program header table up-front. /// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding /// more special-purpose program headers. -pub const number_of_zig_segments = 4; +pub const number_of_zig_segments = 2; const max_number_of_object_segments = 9; const max_number_of_special_phdrs = 5; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 594dd5f640..8cd2341873 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -61,6 +61,7 @@ debug_loclists_index: ?Symbol.Index = null, debug_rnglists_index: ?Symbol.Index = null, eh_frame_index: ?Symbol.Index = null, bss_index: ?Symbol.Index = null, +data_index: ?Symbol.Index = null, pub const global_symbol_bit: u32 = 0x80000000; pub const symbol_mask: u32 = 0x7fffffff; @@ -104,7 +105,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { } }.fillSection; - comptime assert(Elf.number_of_zig_segments == 4); + comptime assert(Elf.number_of_zig_segments == 2); if (!elf_file.base.isRelocatable()) { if (elf_file.phdr_zig_load_re_index == null) { @@ -135,21 +136,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .flags = elf.PF_R | elf.PF_W, }); } - - if (elf_file.phdr_zig_load_rw_index == null) { - const alignment = elf_file.page_size; - const filesz: u64 = 1024; - const off = try elf_file.findFreeSpace(filesz, alignment); - elf_file.phdr_zig_load_rw_index = try elf_file.addPhdr(.{ - .type = elf.PT_LOAD, - .offset = off, - .filesz = filesz, - .addr = if (ptr_size >= 4) 0x10000000 else 0xc000, - .memsz = filesz, - .@"align" = alignment, - .flags = elf.PF_R | elf.PF_W, - }); - } } if (elf_file.zig_text_section_index == null) { @@ -194,27 +180,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { } } - if (elf_file.zig_data_section_index == null) { - elf_file.zig_data_section_index = try elf_file.addSection(.{ - .name = try elf_file.insertShString(".data.zig"), - .type = elf.SHT_PROGBITS, - .addralign = ptr_size, - .flags = elf.SHF_ALLOC | elf.SHF_WRITE, - .offset = std.math.maxInt(u64), - }); - const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_section_index.?]; - const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_section_index.?]; - try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_rw_index); - if (elf_file.base.isRelocatable()) { - _ = try elf_file.addRelaShdr( - try elf_file.insertShString(".rela.data.zig"), - elf_file.zig_data_section_index.?, - ); - } else { - phndx.* = elf_file.phdr_zig_load_rw_index.?; - } - } - switch (comp.config.debug_format) { .strip => {}, .dwarf => |v| { @@ -1246,6 +1211,8 @@ fn getNavShdrIndex( sym_index: Symbol.Index, code: []const u8, ) error{OutOfMemory}!u32 { + const gpa = elf_file.base.comp.gpa; + const ptr_size = elf_file.ptrWidthBytes(); const ip = &zcu.intern_pool; const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; const nav_val = zcu.navValue(nav_index); @@ -1276,7 +1243,19 @@ fn getNavShdrIndex( if (is_const) return elf_file.zig_data_rel_ro_section_index.?; if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu)) return switch (zcu.navFileScope(nav_index).mod.optimize_mode) { - .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, + .Debug, .ReleaseSafe => { + if (self.data_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".data"), + .type = elf.SHT_PROGBITS, + .addralign = ptr_size, + .flags = elf.SHF_ALLOC | elf.SHF_WRITE, + .offset = std.math.maxInt(u64), + }); + self.data_index = try self.addSectionSymbol(gpa, ".data", .@"1", osec); + return osec; + }, .ReleaseFast, .ReleaseSmall => { if (self.bss_index) |symbol_index| return self.symbol(symbol_index).atom(elf_file).?.output_section_index; @@ -1286,7 +1265,7 @@ fn getNavShdrIndex( .name = try elf_file.insertShString(".bss"), .addralign = 1, }); - self.bss_index = try self.addSectionSymbol(elf_file.base.comp.gpa, ".bss", .@"1", osec); + self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec); return osec; }, }; @@ -1302,10 +1281,20 @@ fn getNavShdrIndex( .name = try elf_file.insertShString(".bss"), .addralign = 1, }); - self.bss_index = try self.addSectionSymbol(elf_file.base.comp.gpa, ".bss", .@"1", osec); + self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec); return osec; } - return elf_file.zig_data_section_index.?; + if (self.data_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".data"), + .type = elf.SHT_PROGBITS, + .addralign = ptr_size, + .flags = elf.SHF_ALLOC | elf.SHF_WRITE, + .offset = std.math.maxInt(u64), + }); + self.data_index = try self.addSectionSymbol(gpa, ".data", .@"1", osec); + return osec; } fn updateNavCode( @@ -2014,6 +2003,16 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { } shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?); + const sect_atom_ptr = for ([_]?Symbol.Index{self.data_index}) |maybe_sym_index| { + const sect_sym_index = maybe_sym_index orelse continue; + const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?; + if (sect_atom_ptr.output_section_index == atom_ptr.output_section_index) break sect_atom_ptr; + } else null; + if (sect_atom_ptr) |sap| { + sap.size = shdr.sh_size; + sap.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); + } + // This function can also reallocate an atom. // In this case we need to "unplug" it from its previous location before // plugging it in to its new location. From 848535535d88641a97c6f364cc78171743d7ae81 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 20:56:12 +0200 Subject: [PATCH 06/35] elf: allocate .data.rel.ro and .rodata in ZigObject similarly to .eh_frame --- src/link/Elf.zig | 9 ++-- src/link/Elf/ZigObject.zig | 101 ++++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 48 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ae6933fdf7..018cdda888 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -57,8 +57,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, /// Tracked loadable segments during incremental linking. /// The index into the program headers of a PT_LOAD program header with Read and Execute flags phdr_zig_load_re_index: ?u16 = null, -/// The index into the program headers of a PT_LOAD program header with Read flag -phdr_zig_load_ro_index: ?u16 = null, /// Special program headers /// PT_PHDR @@ -123,7 +121,6 @@ comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, /// Tracked section headers with incremental updates to Zig object. /// .rela.* sections are only used when emitting a relocatable object file. zig_text_section_index: ?u32 = null, -zig_data_rel_ro_section_index: ?u32 = null, debug_info_section_index: ?u32 = null, debug_abbrev_section_index: ?u32 = null, @@ -3360,7 +3357,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { for (&[_]*?u16{ &self.phdr_zig_load_re_index, - &self.phdr_zig_load_ro_index, &self.phdr_table_index, &self.phdr_table_load_index, &self.phdr_interp_index, @@ -3487,7 +3483,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { &self.versym_section_index, &self.verneed_section_index, &self.zig_text_section_index, - &self.zig_data_rel_ro_section_index, &self.debug_info_section_index, &self.debug_abbrev_section_index, &self.debug_str_section_index, @@ -3588,6 +3583,7 @@ fn updateSectionSizes(self: *Elf) !void { if (self.zigObjectPtr()) |zo| blk: { const sym_index = for ([_]?Symbol.Index{ zo.data_index, + zo.data_relro_index, zo.bss_index, }) |maybe_idx| { if (maybe_idx) |idx| break idx; @@ -3932,6 +3928,7 @@ pub fn allocateAllocSections(self: *Elf) !void { if (self.zigObjectPtr()) |zo| blk: { const existing_size = for ([_]?Symbol.Index{ zo.data_index, + zo.data_relro_index, zo.eh_frame_index, }) |maybe_sym_index| { const sect_sym_index = maybe_sym_index orelse continue; @@ -4105,6 +4102,7 @@ fn writeAtoms(self: *Elf) !void { } else if (self.zigObjectPtr()) |zo| base_offset: { const sym_index = for ([_]?Symbol.Index{ zo.data_index, + zo.data_relro_index, zo.eh_frame_index, }) |maybe_idx| { if (maybe_idx) |idx| break idx; @@ -4818,7 +4816,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool { pub fn isZigSection(self: Elf, shndx: u32) bool { inline for (&[_]?u32{ self.zig_text_section_index, - self.zig_data_rel_ro_section_index, }) |index| { if (index == shndx) return true; } diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 8cd2341873..2ebe82e866 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -62,6 +62,8 @@ debug_rnglists_index: ?Symbol.Index = null, eh_frame_index: ?Symbol.Index = null, bss_index: ?Symbol.Index = null, data_index: ?Symbol.Index = null, +data_relro_index: ?Symbol.Index = null, +rodata_index: ?Symbol.Index = null, pub const global_symbol_bit: u32 = 0x80000000; pub const symbol_mask: u32 = 0x7fffffff; @@ -121,21 +123,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .flags = elf.PF_X | elf.PF_R | elf.PF_W, }); } - - if (elf_file.phdr_zig_load_ro_index == null) { - const alignment = elf_file.page_size; - const filesz: u64 = 1024; - const off = try elf_file.findFreeSpace(filesz, alignment); - elf_file.phdr_zig_load_ro_index = try elf_file.addPhdr(.{ - .type = elf.PT_LOAD, - .offset = off, - .filesz = filesz, - .addr = if (ptr_size >= 4) 0xc000000 else 0xa000, - .memsz = filesz, - .@"align" = alignment, - .flags = elf.PF_R | elf.PF_W, - }); - } } if (elf_file.zig_text_section_index == null) { @@ -159,27 +146,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { } } - if (elf_file.zig_data_rel_ro_section_index == null) { - elf_file.zig_data_rel_ro_section_index = try elf_file.addSection(.{ - .name = try elf_file.insertShString(".data.rel.ro.zig"), - .type = elf.SHT_PROGBITS, - .addralign = 1, - .flags = elf.SHF_ALLOC | elf.SHF_WRITE, - .offset = std.math.maxInt(u64), - }); - const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_rel_ro_section_index.?]; - const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_rel_ro_section_index.?]; - try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_ro_index); - if (elf_file.base.isRelocatable()) { - _ = try elf_file.addRelaShdr( - try elf_file.insertShString(".rela.data.rel.ro.zig"), - elf_file.zig_data_rel_ro_section_index.?, - ); - } else { - phndx.* = elf_file.phdr_zig_load_ro_index.?; - } - } - switch (comp.config.debug_format) { .strip => {}, .dwarf => |v| { @@ -1083,6 +1049,20 @@ pub fn lowerUav( return .{ .mcv = .{ .load_symbol = metadata.symbol_index } }; } + const osec = if (self.data_relro_index) |sym_index| + self.symbol(sym_index).atom(elf_file).?.output_section_index + else osec: { + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".data.rel.ro"), + .type = elf.SHT_PROGBITS, + .addralign = 1, + .flags = elf.SHF_ALLOC | elf.SHF_WRITE, + .offset = std.math.maxInt(u64), + }); + self.data_relro_index = osec; + break :osec osec; + }; + var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ @intFromEnum(uav), @@ -1093,7 +1073,7 @@ pub fn lowerUav( name, val, uav_alignment, - elf_file.zig_data_rel_ro_section_index.?, + osec, src_loc, ) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, @@ -1240,7 +1220,19 @@ fn getNavShdrIndex( .offset = std.math.maxInt(u64), }); } - if (is_const) return elf_file.zig_data_rel_ro_section_index.?; + if (is_const) { + if (self.data_relro_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".data.rel.ro"), + .type = elf.SHT_PROGBITS, + .addralign = 1, + .flags = elf.SHF_ALLOC | elf.SHF_WRITE, + .offset = std.math.maxInt(u64), + }); + self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec); + return osec; + } if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu)) return switch (zcu.navFileScope(nav_index).mod.optimize_mode) { .Debug, .ReleaseSafe => { @@ -1253,7 +1245,12 @@ fn getNavShdrIndex( .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .offset = std.math.maxInt(u64), }); - self.data_index = try self.addSectionSymbol(gpa, ".data", .@"1", osec); + self.data_index = try self.addSectionSymbol( + gpa, + ".data", + Atom.Alignment.fromNonzeroByteUnits(ptr_size), + osec, + ); return osec; }, .ReleaseFast, .ReleaseSmall => { @@ -1293,7 +1290,12 @@ fn getNavShdrIndex( .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .offset = std.math.maxInt(u64), }); - self.data_index = try self.addSectionSymbol(gpa, ".data", .@"1", osec); + self.data_index = try self.addSectionSymbol( + gpa, + ".data", + Atom.Alignment.fromNonzeroByteUnits(ptr_size), + osec, + ); return osec; } @@ -1702,7 +1704,19 @@ fn updateLazySymbol( const output_section_index = switch (sym.kind) { .code => elf_file.zig_text_section_index.?, - .const_data => elf_file.zig_data_rel_ro_section_index.?, + .const_data => if (self.rodata_index) |sym_index| + self.symbol(sym_index).atom(elf_file).?.output_section_index + else osec: { + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".rodata"), + .type = elf.SHT_PROGBITS, + .addralign = 1, + .flags = elf.SHF_ALLOC, + .offset = std.math.maxInt(u64), + }); + self.rodata_index = try self.addSectionSymbol(gpa, ".rodata", .@"1", osec); + break :osec osec; + }, }; const local_sym = self.symbol(symbol_index); local_sym.name_offset = name_str_index; @@ -2003,7 +2017,10 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { } shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?); - const sect_atom_ptr = for ([_]?Symbol.Index{self.data_index}) |maybe_sym_index| { + const sect_atom_ptr = for ([_]?Symbol.Index{ + self.data_index, + self.data_relro_index, + }) |maybe_sym_index| { const sect_sym_index = maybe_sym_index orelse continue; const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?; if (sect_atom_ptr.output_section_index == atom_ptr.output_section_index) break sect_atom_ptr; From 2d0f4fc9c0401a3c0fcf68dfc67c7948351c7f73 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 21:14:46 +0200 Subject: [PATCH 07/35] elf: allocate .text in ZigObject similarly to .eh_frame --- src/link/Elf.zig | 23 +------- src/link/Elf/ZigObject.zig | 109 ++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 84 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 018cdda888..813d0c3afc 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -54,10 +54,6 @@ shdr_table_offset: ?u64 = null, /// Same order as in the file. phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, -/// Tracked loadable segments during incremental linking. -/// The index into the program headers of a PT_LOAD program header with Read and Execute flags -phdr_zig_load_re_index: ?u16 = null, - /// Special program headers /// PT_PHDR phdr_table_index: ?u16 = null, @@ -118,10 +114,6 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, /// Applies only to a relocatable. comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, -/// Tracked section headers with incremental updates to Zig object. -/// .rela.* sections are only used when emitting a relocatable object file. -zig_text_section_index: ?u32 = null, - debug_info_section_index: ?u32 = null, debug_abbrev_section_index: ?u32 = null, debug_str_section_index: ?u32 = null, @@ -3356,7 +3348,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { } for (&[_]*?u16{ - &self.phdr_zig_load_re_index, &self.phdr_table_index, &self.phdr_table_load_index, &self.phdr_interp_index, @@ -3482,7 +3473,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { &self.copy_rel_section_index, &self.versym_section_index, &self.verneed_section_index, - &self.zig_text_section_index, &self.debug_info_section_index, &self.debug_abbrev_section_index, &self.debug_str_section_index, @@ -3734,10 +3724,9 @@ fn getMaxNumberOfPhdrs() u64 { /// We permit a maximum of 3**2 number of segments. fn calcNumberOfSegments(self: *Elf) usize { var covers: [9]bool = [_]bool{false} ** 9; - for (self.sections.items(.shdr), 0..) |shdr, shndx| { + for (self.sections.items(.shdr)) |shdr| { if (shdr.sh_type == elf.SHT_NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; - if (self.isZigSection(@intCast(shndx))) continue; const flags = shdrToPhdrFlags(shdr.sh_flags); covers[flags - 1] = true; } @@ -3835,7 +3824,6 @@ pub fn allocateAllocSections(self: *Elf) !void { for (slice.items(.shdr), 0..) |shdr, shndx| { if (shdr.sh_type == elf.SHT_NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; - if (self.isZigSection(@intCast(shndx))) continue; const flags = shdrToPhdrFlags(shdr.sh_flags); try covers[flags - 1].append(@intCast(shndx)); } @@ -4813,15 +4801,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool { }; } -pub fn isZigSection(self: Elf, shndx: u32) bool { - inline for (&[_]?u32{ - self.zig_text_section_index, - }) |index| { - if (index == shndx) return true; - } - return false; -} - pub fn isDebugSection(self: Elf, shndx: u32) bool { inline for (&[_]?u32{ self.debug_info_section_index, diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 2ebe82e866..39df4b78cc 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -51,6 +51,12 @@ debug_loclists_section_dirty: bool = false, debug_rnglists_section_dirty: bool = false, eh_frame_section_dirty: bool = false, +text_index: ?Symbol.Index = null, +data_relro_index: ?Symbol.Index = null, +rodata_index: ?Symbol.Index = null, +data_index: ?Symbol.Index = null, +bss_index: ?Symbol.Index = null, +eh_frame_index: ?Symbol.Index = null, debug_info_index: ?Symbol.Index = null, debug_abbrev_index: ?Symbol.Index = null, debug_aranges_index: ?Symbol.Index = null, @@ -59,11 +65,6 @@ debug_line_index: ?Symbol.Index = null, debug_line_str_index: ?Symbol.Index = null, debug_loclists_index: ?Symbol.Index = null, debug_rnglists_index: ?Symbol.Index = null, -eh_frame_index: ?Symbol.Index = null, -bss_index: ?Symbol.Index = null, -data_index: ?Symbol.Index = null, -data_relro_index: ?Symbol.Index = null, -rodata_index: ?Symbol.Index = null, pub const global_symbol_bit: u32 = 0x80000000; pub const symbol_mask: u32 = 0x7fffffff; @@ -75,6 +76,7 @@ const InitOptions = struct { }; pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { + _ = options; const comp = elf_file.base.comp; const gpa = comp.gpa; const ptr_size = elf_file.ptrWidthBytes(); @@ -92,60 +94,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { esym.st_shndx = elf.SHN_ABS; } - const fillSection = struct { - fn fillSection(ef: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) !void { - if (ef.base.isRelocatable()) { - const off = try ef.findFreeSpace(size, shdr.sh_addralign); - shdr.sh_offset = off; - shdr.sh_size = size; - } else { - const phdr = ef.phdrs.items[phndx.?]; - shdr.sh_addr = phdr.p_vaddr; - shdr.sh_offset = phdr.p_offset; - shdr.sh_size = phdr.p_memsz; - } - } - }.fillSection; - - comptime assert(Elf.number_of_zig_segments == 2); - - if (!elf_file.base.isRelocatable()) { - if (elf_file.phdr_zig_load_re_index == null) { - const filesz = options.program_code_size_hint; - const off = try elf_file.findFreeSpace(filesz, elf_file.page_size); - elf_file.phdr_zig_load_re_index = try elf_file.addPhdr(.{ - .type = elf.PT_LOAD, - .offset = off, - .filesz = filesz, - .addr = if (ptr_size >= 4) 0x4000000 else 0x4000, - .memsz = filesz, - .@"align" = elf_file.page_size, - .flags = elf.PF_X | elf.PF_R | elf.PF_W, - }); - } - } - - if (elf_file.zig_text_section_index == null) { - elf_file.zig_text_section_index = try elf_file.addSection(.{ - .name = try elf_file.insertShString(".text.zig"), - .type = elf.SHT_PROGBITS, - .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, - .addralign = 1, - .offset = std.math.maxInt(u64), - }); - const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_text_section_index.?]; - const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_text_section_index.?]; - try fillSection(elf_file, shdr, options.program_code_size_hint, elf_file.phdr_zig_load_re_index); - if (elf_file.base.isRelocatable()) { - _ = try elf_file.addRelaShdr( - try elf_file.insertShString(".rela.text.zig"), - elf_file.zig_text_section_index.?, - ); - } else { - phndx.* = elf_file.phdr_zig_load_re_index.?; - } - } - switch (comp.config.debug_format) { .strip => {}, .dwarf => |v| { @@ -1196,7 +1144,19 @@ fn getNavShdrIndex( const ip = &zcu.intern_pool; const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; const nav_val = zcu.navValue(nav_index); - if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return elf_file.zig_text_section_index.?; + if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) { + if (self.text_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .type = elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, + .name = try elf_file.insertShString(".text"), + .addralign = 1, + .offset = std.math.maxInt(u64), + }); + self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec); + return osec; + } const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { .variable => |variable| .{ false, variable.is_threadlocal, variable.init }, .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, @@ -1538,6 +1498,19 @@ pub fn updateFunc( self.symbol(sym_index).name(elf_file), }); defer gpa.free(name); + const osec = if (self.text_index) |sect_sym_index| + self.symbol(sect_sym_index).atom(elf_file).?.output_section_index + else osec: { + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".text"), + .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, + .type = elf.SHT_PROGBITS, + .addralign = 1, + .offset = std.math.maxInt(u64), + }); + self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec); + break :osec osec; + }; const name_off = try self.addString(gpa, name); const tr_size = trampolineSize(elf_file.getTarget().cpu.arch); const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off); @@ -1549,7 +1522,7 @@ pub fn updateFunc( tr_atom_ptr.value = old_rva; tr_atom_ptr.alive = true; tr_atom_ptr.alignment = old_alignment; - tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?; + tr_atom_ptr.output_section_index = osec; tr_atom_ptr.size = tr_size; const target_sym = self.symbol(sym_index); target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file); @@ -1703,7 +1676,19 @@ fn updateLazySymbol( }; const output_section_index = switch (sym.kind) { - .code => elf_file.zig_text_section_index.?, + .code => if (self.text_index) |sym_index| + self.symbol(sym_index).atom(elf_file).?.output_section_index + else osec: { + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".text"), + .type = elf.SHT_PROGBITS, + .addralign = 1, + .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, + .offset = std.math.maxInt(u64), + }); + self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec); + break :osec osec; + }, .const_data => if (self.rodata_index) |sym_index| self.symbol(sym_index).atom(elf_file).?.output_section_index else osec: { From ef6ee90ff8762624852ee9a71241bd5a926371ab Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 21:19:16 +0200 Subject: [PATCH 08/35] elf: remove now unused number_of_zig_segments --- src/link/Elf.zig | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 813d0c3afc..180314918f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3708,13 +3708,11 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 { /// (This is an upper bound so that we can reserve enough space for the header and progam header /// table without running out of space and being forced to move things around.) fn getMaxNumberOfPhdrs() u64 { - // First, assume we compile Zig's source incrementally, this gives us: - var num: u64 = number_of_zig_segments; - // Next, the estimated maximum number of segments the linker can emit for input sections are: - num += max_number_of_object_segments; - // Next, any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP: + // The estimated maximum number of segments the linker can emit for input sections are: + var num: u64 = max_number_of_object_segments; + // Any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP: num += max_number_of_special_phdrs; - // Finally, PHDR program header and corresponding read-only load segment: + // PHDR program header and corresponding read-only load segment: num += 2; return num; } @@ -5495,7 +5493,6 @@ fn requiresThunks(self: Elf) bool { /// so that we reserve enough space for the program header table up-front. /// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding /// more special-purpose program headers. -pub const number_of_zig_segments = 2; const max_number_of_object_segments = 9; const max_number_of_special_phdrs = 5; From bc39bddd5fd66037bc524bb7c824230fbb249e01 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 22:08:36 +0200 Subject: [PATCH 09/35] elf: remove isDebugSection helper --- src/link/Elf.zig | 97 +++++++++++++++--------------------- src/link/Elf/ZigObject.zig | 4 +- src/link/Elf/relocatable.zig | 24 ++++----- 3 files changed, 54 insertions(+), 71 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 180314918f..d44892836c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3572,8 +3572,10 @@ fn updateSectionSizes(self: *Elf) !void { if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; if (self.zigObjectPtr()) |zo| blk: { const sym_index = for ([_]?Symbol.Index{ - zo.data_index, + zo.text_index, + zo.rodata_index, zo.data_relro_index, + zo.data_index, zo.bss_index, }) |maybe_idx| { if (maybe_idx) |idx| break idx; @@ -3913,8 +3915,10 @@ pub fn allocateAllocSections(self: *Elf) !void { if (self.zigObjectPtr()) |zo| blk: { const existing_size = for ([_]?Symbol.Index{ - zo.data_index, + zo.text_index, + zo.rodata_index, zo.data_relro_index, + zo.data_index, zo.eh_frame_index, }) |maybe_sym_index| { const sect_sym_index = maybe_sym_index orelse continue; @@ -3954,27 +3958,27 @@ pub fn allocateNonAllocSections(self: *Elf) !void { shdr.sh_size = 0; const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign); - if (self.isDebugSection(@intCast(shndx))) { + if (self.zigObjectPtr()) |zo| blk: { + const existing_size = for ([_]?Symbol.Index{ + zo.debug_info_index, + zo.debug_abbrev_index, + zo.debug_aranges_index, + zo.debug_str_index, + zo.debug_line_index, + zo.debug_line_str_index, + zo.debug_loclists_index, + zo.debug_rnglists_index, + }) |maybe_sym_index| { + const sym_index = maybe_sym_index orelse continue; + const sym = zo.symbol(sym_index); + const atom_ptr = sym.atom(self).?; + if (atom_ptr.output_section_index == shndx) break atom_ptr.size; + } else break :blk; log.debug("moving {s} from 0x{x} to 0x{x}", .{ self.getShString(shdr.sh_name), shdr.sh_offset, new_offset, }); - const zo = self.zigObjectPtr().?; - const existing_size = for ([_]Symbol.Index{ - zo.debug_info_index.?, - zo.debug_abbrev_index.?, - zo.debug_aranges_index.?, - zo.debug_str_index.?, - zo.debug_line_index.?, - zo.debug_line_str_index.?, - zo.debug_loclists_index.?, - zo.debug_rnglists_index.?, - }) |sym_index| { - const sym = zo.symbol(sym_index); - const atom_ptr = sym.atom(self).?; - if (atom_ptr.output_section_index == shndx) break atom_ptr.size; - } else 0; const amt = try self.base.file.?.copyRangeAll( shdr.sh_offset, self.base.file.?, @@ -4068,35 +4072,28 @@ fn writeAtoms(self: *Elf) !void { log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); // TODO really, really handle debug section separately - const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: { - const zo = self.zigObjectPtr().?; - for ([_]Symbol.Index{ - zo.debug_info_index.?, - zo.debug_abbrev_index.?, - zo.debug_aranges_index.?, - zo.debug_str_index.?, - zo.debug_line_index.?, - zo.debug_line_str_index.?, - zo.debug_loclists_index.?, - zo.debug_rnglists_index.?, - }) |sym_index| { + const base_offset = if (self.zigObjectPtr()) |zo| base_offset: { + for ([_]?Symbol.Index{ + zo.text_index, + zo.rodata_index, + zo.data_relro_index, + zo.data_index, + zo.eh_frame_index, + zo.debug_info_index, + zo.debug_abbrev_index, + zo.debug_aranges_index, + zo.debug_str_index, + zo.debug_line_index, + zo.debug_line_str_index, + zo.debug_loclists_index, + zo.debug_rnglists_index, + }) |maybe_sym_index| { + const sym_index = maybe_sym_index orelse continue; const sym = zo.symbol(sym_index); const atom_ptr = sym.atom(self).?; if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size; } break :base_offset 0; - } else if (self.zigObjectPtr()) |zo| base_offset: { - const sym_index = for ([_]?Symbol.Index{ - zo.data_index, - zo.data_relro_index, - zo.eh_frame_index, - }) |maybe_idx| { - if (maybe_idx) |idx| break idx; - } else break :base_offset 0; - const sym = zo.symbol(sym_index); - const atom_ptr = sym.atom(self).?; - if (atom_ptr.output_section_index == @as(u32, @intCast(shndx))) break :base_offset atom_ptr.size; - break :base_offset 0; } else 0; const sh_offset = shdr.sh_offset + base_offset; const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; @@ -4799,22 +4796,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool { }; } -pub fn isDebugSection(self: Elf, shndx: u32) bool { - inline for (&[_]?u32{ - self.debug_info_section_index, - self.debug_abbrev_section_index, - self.debug_str_section_index, - self.debug_aranges_section_index, - self.debug_line_section_index, - self.debug_line_str_section_index, - self.debug_loclists_section_index, - self.debug_rnglists_section_index, - }) |index| { - if (index == shndx) return true; - } - return false; -} - pub fn addPhdr(self: *Elf, opts: struct { type: u32 = 0, flags: u32 = 0, diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 39df4b78cc..0173ffb40b 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -52,8 +52,8 @@ debug_rnglists_section_dirty: bool = false, eh_frame_section_dirty: bool = false, text_index: ?Symbol.Index = null, -data_relro_index: ?Symbol.Index = null, rodata_index: ?Symbol.Index = null, +data_relro_index: ?Symbol.Index = null, data_index: ?Symbol.Index = null, bss_index: ?Symbol.Index = null, eh_frame_index: ?Symbol.Index = null, @@ -2003,6 +2003,8 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?); const sect_atom_ptr = for ([_]?Symbol.Index{ + self.text_index, + self.rodata_index, self.data_index, self.data_relro_index, }) |maybe_sym_index| { diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 8f5ea8e25b..4397bc2ca3 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -436,18 +436,18 @@ fn writeAtoms(elf_file: *Elf) !void { log.debug("writing atoms in '{s}' section", .{elf_file.getShString(shdr.sh_name)}); // TODO really, really handle debug section separately - const base_offset = if (elf_file.isDebugSection(@intCast(shndx))) blk: { - const zo = elf_file.zigObjectPtr().?; - break :blk for ([_]Symbol.Index{ - zo.debug_info_index.?, - zo.debug_abbrev_index.?, - zo.debug_aranges_index.?, - zo.debug_str_index.?, - zo.debug_line_index.?, - zo.debug_line_str_index.?, - zo.debug_loclists_index.?, - zo.debug_rnglists_index.?, - }) |sym_index| { + const base_offset = if (elf_file.zigObjectPtr()) |zo| blk: { + break :blk for ([_]?Symbol.Index{ + zo.debug_info_index, + zo.debug_abbrev_index, + zo.debug_aranges_index, + zo.debug_str_index, + zo.debug_line_index, + zo.debug_line_str_index, + zo.debug_loclists_index, + zo.debug_rnglists_index, + }) |maybe_sym_index| { + const sym_index = maybe_sym_index orelse continue; const sym = zo.symbol(sym_index); const atom_ptr = sym.atom(elf_file).?; if (atom_ptr.output_section_index == shndx) break atom_ptr.size; From 25fa092bb1940ccd88f413a6ebe0a5d4d3befa71 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 22:41:57 +0200 Subject: [PATCH 10/35] elf: fix a typo in setting ZigObject.data_relro_index --- src/link/Elf/ZigObject.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 0173ffb40b..9e42a53ccb 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1007,7 +1007,7 @@ pub fn lowerUav( .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .offset = std.math.maxInt(u64), }); - self.data_relro_index = osec; + self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec); break :osec osec; }; From acb91f4b30e6cbb14bb81406ca6ca71241dc3a98 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 29 Aug 2024 23:23:39 +0200 Subject: [PATCH 11/35] elf: fix emitting correct .rela. sections in -r mode --- src/link/Elf/ZigObject.zig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 9e42a53ccb..27fb121b04 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -494,14 +494,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi } } } - - if (elf_file.base.isRelocatable() and relocs.items.len > 0) { - const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{elf_file.getShString(shdr.sh_name)}); - defer gpa.free(rela_sect_name); - if (elf_file.sectionByName(rela_sect_name) == null) { - _ = try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), shndx); - } - } } self.debug_abbrev_section_dirty = false; @@ -820,6 +812,7 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { } pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; @@ -829,11 +822,18 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { const out_shndx = atom_ptr.output_section_index; const out_shdr = elf_file.sections.items(.shdr)[out_shndx]; if (out_shdr.sh_type == elf.SHT_NOBITS) continue; - const out_rela_shndx = for (elf_file.sections.items(.shdr), 0..) |out_rela_shdr, out_rela_shndx| { - if (out_rela_shdr.sh_type == elf.SHT_RELA and out_rela_shdr.sh_info == out_shndx) break out_rela_shndx; - } else unreachable; + const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{ + elf_file.getShString(out_shdr.sh_name), + }); + defer gpa.free(rela_sect_name); + const out_rela_shndx = if (elf_file.sectionByName(rela_sect_name)) |out_rela_shndx| + out_rela_shndx + else + try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), out_shndx); + const out_rela_shdr = &elf_file.sections.items(.shdr)[out_rela_shndx]; + out_rela_shdr.sh_info = out_shndx; + out_rela_shdr.sh_link = elf_file.symtab_section_index.?; const atom_list = &elf_file.sections.items(.atom_list)[out_rela_shndx]; - const gpa = elf_file.base.comp.gpa; try atom_list.append(gpa, .{ .index = atom_index, .file = self.index }); } } From da60159d85f2b23e35b62f0626163d798413916f Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 30 Aug 2024 11:34:21 +0200 Subject: [PATCH 12/35] elf+dwarf: refer sections via section symbols --- src/link/Dwarf.zig | 85 +++++++++++++++++++++----------------- src/link/Elf.zig | 61 +++++++++++---------------- src/link/Elf/ZigObject.zig | 60 ++++++++++++--------------- 3 files changed, 100 insertions(+), 106 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index c3197f7651..332c79e0fc 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -375,12 +375,17 @@ pub const Section = struct { fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void { if (len <= sec.len) return; if (dwarf.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(sec.index).atom(elf_file).?; + const shndx = atom.output_section_index; if (sec == &dwarf.debug_frame.section) - try elf_file.growAllocSection(sec.index, len) + try elf_file.growAllocSection(shndx, len) else - try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true); - const shdr = &elf_file.sections.items(.shdr)[sec.index]; - sec.off = shdr.sh_offset; + try elf_file.growNonAllocSection(shndx, len, @intCast(sec.alignment.toByteUnits().?), true); + const shdr = elf_file.sections.items(.shdr)[shndx]; + atom.size = shdr.sh_size; + atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); + sec.off = shdr.sh_offset + @as(u64, @intCast(atom.value)); sec.len = shdr.sh_size; } else if (dwarf.bin_file.cast(.macho)) |macho_file| { const header = if (macho_file.d_sym) |*d_sym| header: { @@ -402,7 +407,11 @@ pub const Section = struct { sec.off += len; sec.len -= len; if (dwarf.bin_file.cast(.elf)) |elf_file| { - const shdr = &elf_file.sections.items(.shdr)[sec.index]; + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(sec.index).atom(elf_file).?; + const shndx = atom.output_section_index; + const shdr = &elf_file.sections.items(.shdr)[shndx]; + atom.size = sec.len; shdr.sh_offset = sec.off; shdr.sh_size = sec.len; } else if (dwarf.bin_file.cast(.macho)) |macho_file| { @@ -891,9 +900,11 @@ const Entry = struct { if (std.debug.runtime_safety) { log.err("missing {} from {s}", .{ @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)), - std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| - elf_file.shstrtab.items[elf_file.sections.items(.shdr)[sec.index].sh_name..] - else if (dwarf.bin_file.cast(.macho)) |macho_file| + std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| sh_name: { + const zo = elf_file.zigObjectPtr().?; + const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index; + break :sh_name elf_file.shstrtab.items[elf_file.sections.items(.shdr)[shndx].sh_name..]; + } else if (dwarf.bin_file.cast(.macho)) |macho_file| if (macho_file.d_sym) |*d_sym| &d_sym.sections.items[sec.index].segname else @@ -961,7 +972,8 @@ const Entry = struct { .none, .debug_frame => {}, .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; - const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[sec.index].sh_addr); + const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index; + const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[shndx].sh_addr); for (entry.external_relocs.items) |reloc| { const symbol = zo.symbol(reloc.target_sym); try dwarf.resolveReloc( @@ -1877,34 +1889,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { } pub fn reloadSectionMetadata(dwarf: *Dwarf) void { - if (dwarf.bin_file.cast(.elf)) |elf_file| { - for ([_]*Section{ - &dwarf.debug_abbrev.section, - &dwarf.debug_aranges.section, - &dwarf.debug_frame.section, - &dwarf.debug_info.section, - &dwarf.debug_line.section, - &dwarf.debug_line_str.section, - &dwarf.debug_loclists.section, - &dwarf.debug_rnglists.section, - &dwarf.debug_str.section, - }, [_]u32{ - elf_file.debug_abbrev_section_index.?, - elf_file.debug_aranges_section_index.?, - elf_file.eh_frame_section_index.?, - elf_file.debug_info_section_index.?, - elf_file.debug_line_section_index.?, - elf_file.debug_line_str_section_index.?, - elf_file.debug_loclists_section_index.?, - elf_file.debug_rnglists_section_index.?, - elf_file.debug_str_section_index.?, - }) |sec, section_index| { - const shdr = &elf_file.sections.items(.shdr)[section_index]; - sec.index = section_index; - sec.off = shdr.sh_offset; - sec.len = shdr.sh_size; - } - } else if (dwarf.bin_file.cast(.macho)) |macho_file| { + if (dwarf.bin_file.cast(.macho)) |macho_file| { if (macho_file.d_sym) |*d_sym| { for ([_]*Section{ &dwarf.debug_abbrev.section, @@ -1960,6 +1945,32 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void { } pub fn initMetadata(dwarf: *Dwarf) UpdateError!void { + if (dwarf.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + for ([_]*Section{ + &dwarf.debug_abbrev.section, + &dwarf.debug_aranges.section, + &dwarf.debug_frame.section, + &dwarf.debug_info.section, + &dwarf.debug_line.section, + &dwarf.debug_line_str.section, + &dwarf.debug_loclists.section, + &dwarf.debug_rnglists.section, + &dwarf.debug_str.section, + }, [_]u32{ + zo.debug_abbrev_index.?, + zo.debug_aranges_index.?, + zo.eh_frame_index.?, + zo.debug_info_index.?, + zo.debug_line_index.?, + zo.debug_line_str_index.?, + zo.debug_loclists_index.?, + zo.debug_rnglists_index.?, + zo.debug_str_index.?, + }) |sec, sym_index| { + sec.index = sym_index; + } + } dwarf.reloadSectionMetadata(); dwarf.debug_abbrev.section.pad_to_ideal = false; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d44892836c..2940759009 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -114,15 +114,6 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, /// Applies only to a relocatable. comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, -debug_info_section_index: ?u32 = null, -debug_abbrev_section_index: ?u32 = null, -debug_str_section_index: ?u32 = null, -debug_aranges_section_index: ?u32 = null, -debug_line_section_index: ?u32 = null, -debug_line_str_section_index: ?u32 = null, -debug_loclists_section_index: ?u32 = null, -debug_rnglists_section_index: ?u32 = null, - copy_rel_section_index: ?u32 = null, dynamic_section_index: ?u32 = null, dynstrtab_section_index: ?u32 = null, @@ -636,24 +627,31 @@ pub fn growNonAllocSection( } pub fn markDirty(self: *Elf, shdr_index: u32) void { - const zig_object = self.zigObjectPtr().?; - if (zig_object.dwarf) |_| { - if (self.debug_info_section_index.? == shdr_index) { - zig_object.debug_info_section_dirty = true; - } else if (self.debug_abbrev_section_index.? == shdr_index) { - zig_object.debug_abbrev_section_dirty = true; - } else if (self.debug_str_section_index.? == shdr_index) { - zig_object.debug_str_section_dirty = true; - } else if (self.debug_aranges_section_index.? == shdr_index) { - zig_object.debug_aranges_section_dirty = true; - } else if (self.debug_line_section_index.? == shdr_index) { - zig_object.debug_line_section_dirty = true; - } else if (self.debug_line_str_section_index.? == shdr_index) { - zig_object.debug_line_str_section_dirty = true; - } else if (self.debug_loclists_section_index.? == shdr_index) { - zig_object.debug_loclists_section_dirty = true; - } else if (self.debug_rnglists_section_index.? == shdr_index) { - zig_object.debug_rnglists_section_dirty = true; + if (self.zigObjectPtr()) |zo| { + for ([_]?Symbol.Index{ + zo.debug_info_index, + zo.debug_abbrev_index, + zo.debug_aranges_index, + zo.debug_str_index, + zo.debug_line_index, + zo.debug_line_str_index, + zo.debug_loclists_index, + zo.debug_rnglists_index, + }, [_]*bool{ + &zo.debug_info_section_dirty, + &zo.debug_abbrev_section_dirty, + &zo.debug_aranges_section_dirty, + &zo.debug_str_section_dirty, + &zo.debug_line_section_dirty, + &zo.debug_line_str_section_dirty, + &zo.debug_loclists_section_dirty, + &zo.debug_rnglists_section_dirty, + }) |maybe_sym_index, dirty| { + const sym_index = maybe_sym_index orelse continue; + if (zo.symbol(sym_index).atom(self).?.output_section_index == shdr_index) { + dirty.* = true; + break; + } } } } @@ -3473,14 +3471,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { &self.copy_rel_section_index, &self.versym_section_index, &self.verneed_section_index, - &self.debug_info_section_index, - &self.debug_abbrev_section_index, - &self.debug_str_section_index, - &self.debug_aranges_section_index, - &self.debug_line_section_index, - &self.debug_line_str_section_index, - &self.debug_loclists_section_index, - &self.debug_rnglists_section_index, }) |maybe_index| { if (maybe_index.*) |*index| { index.* = backlinks[index.*]; @@ -3505,7 +3495,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { const atom_ptr = zo.atom(atom_index) orelse continue; atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index]; } - if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata(); } for (self.comdat_group_sections.items) |*cg| { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 27fb121b04..8de8551463 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -99,8 +99,8 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .dwarf => |v| { var dwarf = Dwarf.init(&elf_file.base, v); - if (elf_file.debug_str_section_index == null) { - elf_file.debug_str_section_index = try elf_file.addSection(.{ + if (self.debug_str_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_str"), .flags = elf.SHF_MERGE | elf.SHF_STRINGS, .entsize = 1, @@ -108,51 +108,51 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_str_section_dirty = true; - self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", elf_file.debug_str_section_index.?); + self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", osec); } - if (elf_file.debug_info_section_index == null) { - elf_file.debug_info_section_index = try elf_file.addSection(.{ + if (self.debug_info_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_info"), .type = elf.SHT_PROGBITS, .addralign = 1, }); self.debug_info_section_dirty = true; - self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", elf_file.debug_info_section_index.?); + self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", osec); } - if (elf_file.debug_abbrev_section_index == null) { - elf_file.debug_abbrev_section_index = try elf_file.addSection(.{ + if (self.debug_abbrev_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_abbrev"), .type = elf.SHT_PROGBITS, .addralign = 1, }); self.debug_abbrev_section_dirty = true; - self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", elf_file.debug_abbrev_section_index.?); + self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", osec); } - if (elf_file.debug_aranges_section_index == null) { - elf_file.debug_aranges_section_index = try elf_file.addSection(.{ + if (self.debug_aranges_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_aranges"), .type = elf.SHT_PROGBITS, .addralign = 16, }); self.debug_aranges_section_dirty = true; - self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", elf_file.debug_aranges_section_index.?); + self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", osec); } - if (elf_file.debug_line_section_index == null) { - elf_file.debug_line_section_index = try elf_file.addSection(.{ + if (self.debug_line_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_line"), .type = elf.SHT_PROGBITS, .addralign = 1, }); self.debug_line_section_dirty = true; - self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", elf_file.debug_line_section_index.?); + self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", osec); } - if (elf_file.debug_line_str_section_index == null) { - elf_file.debug_line_str_section_index = try elf_file.addSection(.{ + if (self.debug_line_str_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_line_str"), .flags = elf.SHF_MERGE | elf.SHF_STRINGS, .entsize = 1, @@ -160,31 +160,31 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = 1, }); self.debug_line_str_section_dirty = true; - self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", elf_file.debug_line_str_section_index.?); + self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", osec); } - if (elf_file.debug_loclists_section_index == null) { - elf_file.debug_loclists_section_index = try elf_file.addSection(.{ + if (self.debug_loclists_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_loclists"), .type = elf.SHT_PROGBITS, .addralign = 1, }); self.debug_loclists_section_dirty = true; - self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", elf_file.debug_loclists_section_index.?); + self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", osec); } - if (elf_file.debug_rnglists_section_index == null) { - elf_file.debug_rnglists_section_index = try elf_file.addSection(.{ + if (self.debug_rnglists_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".debug_rnglists"), .type = elf.SHT_PROGBITS, .addralign = 1, }); self.debug_rnglists_section_dirty = true; - self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?); + self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", osec); } - if (elf_file.eh_frame_section_index == null) { - elf_file.eh_frame_section_index = try elf_file.addSection(.{ + if (self.eh_frame_index == null) { + const osec = try elf_file.addSection(.{ .name = try elf_file.insertShString(".eh_frame"), .type = if (elf_file.getTarget().cpu.arch == .x86_64) elf.SHT_X86_64_UNWIND @@ -194,7 +194,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .addralign = ptr_size, }); self.eh_frame_section_dirty = true; - self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?); + self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec); } try dwarf.initMetadata(); @@ -328,12 +328,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi const sym = self.symbol(sym_index); const atom_ptr = self.atom(sym.ref.index).?; if (!atom_ptr.alive) continue; - const shndx = sym.outputShndx(elf_file).?; - const shdr = elf_file.sections.items(.shdr)[shndx]; - const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; - esym.st_size = shdr.sh_size; - atom_ptr.size = shdr.sh_size; - atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); log.debug("parsing relocs in {s}", .{sym.name(elf_file)}); From 3e100c5daba0f64695eab0bb4216b9d242229ba6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 30 Aug 2024 15:11:10 +0200 Subject: [PATCH 13/35] dwarf: make Section.off a function --- src/link/Dwarf.zig | 63 +++++++++++++++++++++----------------- src/link/Elf.zig | 2 +- src/link/Elf/Atom.zig | 25 +++++++++------ src/link/Elf/ZigObject.zig | 15 +++------ 4 files changed, 56 insertions(+), 49 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 332c79e0fc..97bc15ced8 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -261,7 +261,6 @@ pub const Section = struct { index: u32, first: Unit.Index.Optional, last: Unit.Index.Optional, - off: u64, len: u64, units: std.ArrayListUnmanaged(Unit), @@ -284,9 +283,8 @@ pub const Section = struct { .index = std.math.maxInt(u32), .first = .none, .last = .none, - .off = 0, - .len = 0, .units = .{}, + .len = 0, }; fn deinit(sec: *Section, gpa: std.mem.Allocator) void { @@ -295,6 +293,20 @@ pub const Section = struct { sec.* = undefined; } + fn off(sec: Section, dwarf: *Dwarf) u64 { + if (dwarf.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(sec.index).atom(elf_file).?; + return atom.offset(elf_file); + } else if (dwarf.bin_file.cast(.macho)) |macho_file| { + const header = if (macho_file.d_sym) |d_sym| + d_sym.sections.items[sec.index] + else + macho_file.sections.items(.header)[sec.index]; + return header.offset; + } else unreachable; + } + fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index { const unit: Unit.Index = @enumFromInt(sec.units.items.len); const unit_ptr = try sec.units.addOne(dwarf.gpa); @@ -306,9 +318,9 @@ pub const Section = struct { .next = .none, .first = .none, .last = .none, - .off = 0, .header_len = aligned_header_len, .trailer_len = aligned_trailer_len, + .off = 0, .len = aligned_header_len + aligned_trailer_len, .entries = .{}, .cross_unit_relocs = .{}, @@ -385,7 +397,6 @@ pub const Section = struct { const shdr = elf_file.sections.items(.shdr)[shndx]; atom.size = shdr.sh_size; atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); - sec.off = shdr.sh_offset + @as(u64, @intCast(atom.value)); sec.len = shdr.sh_size; } else if (dwarf.bin_file.cast(.macho)) |macho_file| { const header = if (macho_file.d_sym) |*d_sym| header: { @@ -395,7 +406,6 @@ pub const Section = struct { try macho_file.growSection(@intCast(sec.index), len); break :header &macho_file.sections.items(.header)[sec.index]; }; - sec.off = header.offset; sec.len = header.size; } } @@ -404,7 +414,6 @@ pub const Section = struct { const len = sec.getUnit(sec.first.unwrap() orelse return).off; if (len == 0) return; for (sec.units.items) |*unit| unit.off -= len; - sec.off += len; sec.len -= len; if (dwarf.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; @@ -412,14 +421,14 @@ pub const Section = struct { const shndx = atom.output_section_index; const shdr = &elf_file.sections.items(.shdr)[shndx]; atom.size = sec.len; - shdr.sh_offset = sec.off; + shdr.sh_offset += len; shdr.sh_size = sec.len; } else if (dwarf.bin_file.cast(.macho)) |macho_file| { const header = if (macho_file.d_sym) |*d_sym| &d_sym.sections.items[sec.index] else &macho_file.sections.items(.header)[sec.index]; - header.offset = @intCast(sec.off); + header.offset += @intCast(len); header.size = sec.len; } } @@ -548,9 +557,9 @@ const Unit = struct { fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { if (unit.off == new_off) return; if (try dwarf.getFile().?.copyRangeAll( - sec.off + unit.off, + sec.off(dwarf) + unit.off, dwarf.getFile().?, - sec.off + new_off, + sec.off(dwarf) + new_off, unit.len, ) != unit.len) return error.InputOutput; unit.off = new_off; @@ -582,7 +591,7 @@ const Unit = struct { fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { assert(contents.len == unit.header_len); - try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off); + try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off); } fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { @@ -614,7 +623,7 @@ const Unit = struct { assert(fbs.pos == extended_op_bytes + op_len_bytes); writer.writeByte(DW.LNE.padding) catch unreachable; assert(fbs.pos >= unit.trailer_len and fbs.pos <= len); - return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + start); + return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + start); } var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len); defer trailer.deinit(); @@ -673,11 +682,11 @@ const Unit = struct { assert(trailer.items.len == unit.trailer_len); trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len); assert(trailer.items.len == len); - try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start); + try dwarf.getFile().?.pwriteAll(trailer.items, sec.off(dwarf) + start); } fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { - const unit_off = sec.off + unit.off; + const unit_off = sec.off(dwarf) + unit.off; for (unit.cross_unit_relocs.items) |reloc| { const target_unit = sec.getUnit(reloc.target_unit); try dwarf.resolveReloc( @@ -764,12 +773,12 @@ const Entry = struct { dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes()); try dwarf.getFile().?.pwriteAll( unit_len[0..dwarf.sectionOffsetBytes()], - sec.off + unit.off + unit.header_len + entry.off, + sec.off(dwarf) + unit.off + unit.header_len + entry.off, ); const buf = try dwarf.gpa.alloc(u8, len - entry.len); defer dwarf.gpa.free(buf); @memset(buf, DW.CFA.nop); - try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start); + try dwarf.getFile().?.pwriteAll(buf, sec.off(dwarf) + unit.off + unit.header_len + start); return; } const len = unit.getEntry(entry.next.unwrap() orelse return).off - start; @@ -825,7 +834,7 @@ const Entry = struct { }, } else assert(!sec.pad_to_ideal and len == 0); assert(fbs.pos <= len); - try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start); + try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + unit.off + unit.header_len + start); } fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { @@ -860,15 +869,15 @@ const Entry = struct { fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { assert(contents.len == entry_ptr.len); - try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off); + try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off); if (false) { const buf = try dwarf.gpa.alloc(u8, sec.len); defer dwarf.gpa.free(buf); - _ = try dwarf.getFile().?.preadAll(buf, sec.off); + _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf)); log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{ @intFromEnum(sec.first), @intFromEnum(sec.last), - sec.off, + sec.off(dwarf), sec.len, }); for (sec.units.items) |*unit_ptr| { @@ -935,7 +944,7 @@ const Entry = struct { } fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { - const entry_off = sec.off + unit.off + unit.header_len + entry.off; + const entry_off = sec.off(dwarf) + unit.off + unit.header_len + entry.off; for (entry.cross_entry_relocs.items) |reloc| { try dwarf.resolveReloc( entry_off + reloc.source_off, @@ -973,7 +982,7 @@ const Entry = struct { .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index; - const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[shndx].sh_addr); + const entry_addr: i64 = @intCast(entry_off - sec.off(dwarf) + elf_file.shdrs.items[shndx].sh_addr); for (entry.external_relocs.items) |reloc| { const symbol = zo.symbol(reloc.target_sym); try dwarf.resolveReloc( @@ -1912,7 +1921,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void { }) |sec, sect_index| { const header = &d_sym.sections.items[sect_index]; sec.index = sect_index; - sec.off = header.offset; sec.len = header.size; } } else { @@ -1937,7 +1945,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void { }) |sec, sect_index| { const header = &macho_file.sections.items(.header)[sect_index]; sec.index = sect_index; - sec.off = header.offset; sec.len = header.size; } } @@ -2534,7 +2541,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined; if (try dwarf.getFile().?.preadAll( &abbrev_code_buf, - dwarf.debug_info.section.off + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, + dwarf.debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, ) != abbrev_code_buf.len) return error.InputOutput; var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf); const abbrev_code: AbbrevCode = @enumFromInt( @@ -3945,7 +3952,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_str.section.dirty) { const contents = dwarf.debug_str.contents.items; try dwarf.debug_str.section.resize(dwarf, contents.len); - try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off); + try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off(dwarf)); dwarf.debug_str.section.dirty = false; } if (dwarf.debug_line.section.dirty) { @@ -4051,7 +4058,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { if (dwarf.debug_line_str.section.dirty) { const contents = dwarf.debug_line_str.contents.items; try dwarf.debug_line_str.section.resize(dwarf, contents.len); - try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off); + try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off(dwarf)); dwarf.debug_line_str.section.dirty = false; } if (dwarf.debug_loclists.section.dirty) { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 2940759009..f182a4a868 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1070,7 +1070,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod if (shdr.sh_type == elf.SHT_NOBITS) continue; const code = try zo.codeAlloc(self, atom_index); defer gpa.free(code); - const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); + const file_offset = atom_ptr.offset(self); atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, error.UnsupportedCpuArch => { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 3d1fe04fb5..ab0e98440b 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -51,6 +51,11 @@ pub fn address(self: Atom, elf_file: *Elf) i64 { return @as(i64, @intCast(shdr.sh_addr)) + self.value; } +pub fn offset(self: Atom, elf_file: *Elf) u64 { + const shdr = elf_file.sections.items(.shdr)[self.output_section_index]; + return shdr.sh_offset + @as(u64, @intCast(self.value)); +} + pub fn ref(self: Atom) Elf.Ref { return .{ .index = self.atom_index, .file = self.file_index }; } @@ -1673,7 +1678,7 @@ const aarch64 = struct { => { // TODO: NC means no overflow check const taddr = @as(u64, @intCast(S + A)); - const offset: u12 = switch (r_type) { + const off: u12 = switch (r_type) { .LDST8_ABS_LO12_NC => @truncate(taddr), .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2), .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4), @@ -1681,7 +1686,7 @@ const aarch64 = struct { .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), else => unreachable, }; - aarch64_util.writeLoadStoreRegInst(offset, code); + aarch64_util.writeLoadStoreRegInst(off, code); }, .TLSLE_ADD_TPREL_HI12 => { @@ -1705,8 +1710,8 @@ const aarch64 = struct { .TLSIE_LD64_GOTTPREL_LO12_NC => { const S_ = target.gotTpAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); - aarch64_util.writeLoadStoreRegInst(offset, code); + const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); + aarch64_util.writeLoadStoreRegInst(off, code); }, .TLSGD_ADR_PAGE21 => { @@ -1719,8 +1724,8 @@ const aarch64 = struct { .TLSGD_ADD_LO12_NC => { const S_ = target.tlsGdAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); - aarch64_util.writeAddImmInst(offset, code); + const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); + aarch64_util.writeAddImmInst(off, code); }, .TLSDESC_ADR_PAGE21 => { @@ -1739,8 +1744,8 @@ const aarch64 = struct { if (target.flags.has_tlsdesc) { const S_ = target.tlsDescAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); - aarch64_util.writeLoadStoreRegInst(offset, code); + const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); + aarch64_util.writeLoadStoreRegInst(off, code); } else { relocs_log.debug(" relaxing ldr => nop", .{}); mem.writeInt(u32, code, Instruction.nop().toU32(), .little); @@ -1751,8 +1756,8 @@ const aarch64 = struct { if (target.flags.has_tlsdesc) { const S_ = target.tlsDescAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); - aarch64_util.writeAddImmInst(offset, code); + const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); + aarch64_util.writeAddImmInst(off, code); } else { const old_inst = Instruction{ .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 8de8551463..8f16672591 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -906,7 +906,7 @@ pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 return code; } - const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); + const file_offset = atom_ptr.offset(elf_file); const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow; const code = try gpa.alloc(u8, size); errdefer gpa.free(code); @@ -1338,7 +1338,7 @@ fn updateNavCode( const shdr = elf_file.sections.items(.shdr)[shdr_index]; if (shdr.sh_type != elf.SHT_NOBITS) { - const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); + const file_offset = atom_ptr.offset(elf_file); try elf_file.base.file.?.pwriteAll(code, file_offset); log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); } @@ -1716,9 +1716,7 @@ fn updateLazySymbol( local_sym.value = 0; local_esym.st_value = 0; - const shdr = elf_file.sections.items(.shdr)[output_section_index]; - const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); - try elf_file.base.file.?.pwriteAll(code, file_offset); + try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file)); } const LowerConstResult = union(enum) { @@ -1771,9 +1769,7 @@ fn lowerConst( try self.allocateAtom(atom_ptr, elf_file); errdefer self.freeNavMetadata(elf_file, sym_index); - const shdr = elf_file.sections.items(.shdr)[output_section_index]; - const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); - try elf_file.base.file.?.pwriteAll(code, file_offset); + try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file)); return .{ .ok = sym_index }; } @@ -1935,8 +1931,7 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { const atom_ptr = tr_sym.atom(elf_file).?; - const shdr = elf_file.sections.items(.shdr)[atom_ptr.output_section_index]; - const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); + const fileoff = atom_ptr.offset(elf_file); const source_addr = tr_sym.address(.{}, elf_file); const target_addr = target.address(.{ .trampoline = false }, elf_file); var buf: [max_trampoline_len]u8 = undefined; From 6ec5df3898d594dd97d1b557aa7bdde38a9998b6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 30 Aug 2024 22:40:27 +0200 Subject: [PATCH 14/35] elf: allocate .tdata and .tbss using allocateAtom mechanics --- src/link/Elf.zig | 19 ++-------- src/link/Elf/ZigObject.zig | 78 +++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 54 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f182a4a868..2c1bd34879 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3556,24 +3556,9 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { fn updateSectionSizes(self: *Elf) !void { const slice = self.sections.slice(); - for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { + for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { if (atom_list.items.len == 0) continue; if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; - if (self.zigObjectPtr()) |zo| blk: { - const sym_index = for ([_]?Symbol.Index{ - zo.text_index, - zo.rodata_index, - zo.data_relro_index, - zo.data_index, - zo.bss_index, - }) |maybe_idx| { - if (maybe_idx) |idx| break idx; - } else break :blk; - const atom_ptr = zo.symbol(sym_index).atom(self).?; - if (shndx == atom_ptr.output_section_index) { - shdr.sh_size = atom_ptr.size; - } - } for (atom_list.items) |ref| { const atom_ptr = self.atom(ref) orelse continue; if (!atom_ptr.alive) continue; @@ -3908,6 +3893,7 @@ pub fn allocateAllocSections(self: *Elf) !void { zo.rodata_index, zo.data_relro_index, zo.data_index, + zo.tdata_index, zo.eh_frame_index, }) |maybe_sym_index| { const sect_sym_index = maybe_sym_index orelse continue; @@ -4067,6 +4053,7 @@ fn writeAtoms(self: *Elf) !void { zo.rodata_index, zo.data_relro_index, zo.data_index, + zo.tdata_index, zo.eh_frame_index, zo.debug_info_index, zo.debug_abbrev_index, diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 8f16672591..2d20895d2e 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -56,6 +56,8 @@ rodata_index: ?Symbol.Index = null, data_relro_index: ?Symbol.Index = null, data_index: ?Symbol.Index = null, bss_index: ?Symbol.Index = null, +tdata_index: ?Symbol.Index = null, +tbss_index: ?Symbol.Index = null, eh_frame_index: ?Symbol.Index = null, debug_info_index: ?Symbol.Index = null, debug_abbrev_index: ?Symbol.Index = null, @@ -233,10 +235,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { meta.exports.deinit(allocator); } self.uavs.deinit(allocator); - - for (self.tls_variables.values()) |*tlv| { - tlv.deinit(allocator); - } self.tls_variables.deinit(allocator); if (self.dwarf) |*dwarf| { @@ -898,14 +896,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { const gpa = elf_file.base.comp.gpa; const atom_ptr = self.atom(atom_index).?; - const shdr = &elf_file.sections.items(.shdr)[atom_ptr.output_section_index]; - - if (shdr.sh_flags & elf.SHF_TLS != 0) { - const tlv = self.tls_variables.get(atom_index).?; - const code = try gpa.dupe(u8, tlv.code); - return code; - } - const file_offset = atom_ptr.offset(elf_file); const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow; const code = try gpa.alloc(u8, size); @@ -1161,18 +1151,29 @@ fn getNavShdrIndex( const is_bss = !has_relocs and for (code) |byte| { if (byte != 0) break false; } else true; - if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ - .type = elf.SHT_NOBITS, - .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, - .name = try elf_file.insertShString(".tbss"), - .offset = std.math.maxInt(u64), - }); - return elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{ + if (is_bss) { + if (self.tbss_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".tbss"), + .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, + .type = elf.SHT_NOBITS, + .addralign = 1, + }); + self.tbss_index = try self.addSectionSymbol(gpa, ".tbss", .@"1", osec); + return osec; + } + if (self.tdata_index) |symbol_index| + return self.symbol(symbol_index).atom(elf_file).?.output_section_index; + const osec = try elf_file.addSection(.{ .type = elf.SHT_PROGBITS, .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, .name = try elf_file.insertShString(".tdata"), + .addralign = 1, .offset = std.math.maxInt(u64), }); + self.tdata_index = try self.addSectionSymbol(gpa, ".tdata", .@"1", osec); + return osec; } if (is_const) { if (self.data_relro_index) |symbol_index| @@ -1367,15 +1368,11 @@ fn updateTlv( const atom_ptr = sym.atom(elf_file).?; const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip)); - sym.value = 0; - sym.name_offset = name_offset; - - atom_ptr.output_section_index = shndx; atom_ptr.alive = true; atom_ptr.name_offset = name_offset; + atom_ptr.output_section_index = shndx; sym.name_offset = name_offset; - esym.st_value = 0; esym.st_name = name_offset; esym.st_info = elf.STT_TLS; esym.st_size = code.len; @@ -1383,21 +1380,25 @@ fn updateTlv( atom_ptr.alignment = required_alignment; atom_ptr.size = code.len; + const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); + assert(!gop.found_existing); // TODO incremental updates + + try self.allocateAtom(atom_ptr, elf_file); + sym.value = 0; + esym.st_value = 0; + self.navs.getPtr(nav_index).?.allocated = true; - { - const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); - assert(!gop.found_existing); // TODO incremental updates - gop.value_ptr.* = .{ .symbol_index = sym_index }; - - // We only store the data for the TLV if it's non-zerofill. - if (elf_file.sections.items(.shdr)[shndx].sh_type != elf.SHT_NOBITS) { - gop.value_ptr.code = try gpa.dupe(u8, code); - } + const shdr = elf_file.sections.items(.shdr)[shndx]; + if (shdr.sh_type != elf.SHT_NOBITS) { + const file_offset = atom_ptr.offset(elf_file); + try elf_file.base.file.?.pwriteAll(code, file_offset); + log.debug("writing TLV {s} from 0x{x} to 0x{x}", .{ + atom_ptr.name(elf_file), + file_offset, + file_offset + code.len, + }); } - - const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index]; - try atom_list.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index }); } pub fn updateFunc( @@ -1994,8 +1995,9 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { const sect_atom_ptr = for ([_]?Symbol.Index{ self.text_index, self.rodata_index, - self.data_index, self.data_relro_index, + self.data_index, + self.tdata_index, }) |maybe_sym_index| { const sect_sym_index = maybe_sym_index orelse continue; const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?; @@ -2305,7 +2307,7 @@ const AtomList = std.ArrayListUnmanaged(Atom.Index); const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); -const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); +const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, void); const x86_64 = struct { fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 { From 1ef96f05eb7806d7123919d30f4b672e82a64d75 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 1 Sep 2024 13:51:08 +0200 Subject: [PATCH 15/35] elf: introduce SectionChunk - a container of atoms per object file --- src/link/Elf.zig | 7 ++- src/link/Elf/Object.zig | 114 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 2c1bd34879..cb5db6dec9 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3555,6 +3555,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { } fn updateSectionSizes(self: *Elf) !void { + for (self.objects.items) |index| { + try self.file(index).?.object.allocateAtoms(self); + } + const slice = self.sections.slice(); for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { if (atom_list.items.len == 0) continue; @@ -5334,8 +5338,9 @@ fn fmtDumpState( try writer.print("object({d}) : {}", .{ index, object.fmtPath() }); if (!object.alive) try writer.writeAll(" : [*]"); try writer.writeByte('\n'); - try writer.print("{}{}{}{}{}\n", .{ + try writer.print("{}{}{}{}{}{}\n", .{ object.fmtAtoms(self), + object.fmtSectionChunks(self), object.fmtCies(self), object.fmtFdes(self), object.fmtSymtab(self), diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index c4443bb67e..3337bfb1a2 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -17,6 +17,7 @@ relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, atoms: std.ArrayListUnmanaged(Atom) = .{}, atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{}, atoms_extra: std.ArrayListUnmanaged(u32) = .{}, +section_chunks: std.ArrayListUnmanaged(SectionChunk) = .{}, comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{}, comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, @@ -58,6 +59,10 @@ pub fn deinit(self: *Object, allocator: Allocator) void { self.atoms.deinit(allocator); self.atoms_indexes.deinit(allocator); self.atoms_extra.deinit(allocator); + for (self.section_chunks.items) |*chunk| { + chunk.deinit(allocator); + } + self.section_chunks.deinit(allocator); self.comdat_groups.deinit(allocator); self.comdat_group_data.deinit(allocator); self.relocs.deinit(allocator); @@ -933,11 +938,26 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; const shdr = atom_ptr.inputShdr(elf_file); - _ = try elf_file.initOutputSection(.{ + const osec = try elf_file.initOutputSection(.{ .name = self.getString(shdr.sh_name), .flags = shdr.sh_flags, .type = shdr.sh_type, }); + const chunk = for (self.section_chunks.items) |*chunk| { + if (chunk.output_section_index == osec) break chunk; + } else blk: { + const chunk = try self.section_chunks.addOne(elf_file.base.comp.gpa); + chunk.* = .{ .output_section_index = osec }; + break :blk chunk; + }; + try chunk.atoms.append(elf_file.base.comp.gpa, atom_index); + } +} + +pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { + _ = elf_file; + for (self.section_chunks.items) |*chunk| { + chunk.updateSize(self); } } @@ -1427,6 +1447,29 @@ fn formatAtoms( } } +pub fn fmtSectionChunks(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatSectionChunks) { + return .{ .data = .{ + .object = self, + .elf_file = elf_file, + } }; +} + +fn formatSectionChunks( + ctx: FormatContext, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = unused_fmt_string; + _ = options; + const object = ctx.object; + const elf_file = ctx.elf_file; + try writer.writeAll(" section chunks\n"); + for (object.section_chunks.items) |chunk| { + try writer.print(" {}\n", .{chunk.fmt(elf_file)}); + } +} + pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) { return .{ .data = .{ .object = self, @@ -1528,6 +1571,75 @@ const InArchive = struct { size: u32, }; +const SectionChunk = struct { + value: i64 = 0, + size: u64 = 0, + alignment: Atom.Alignment = .@"1", + output_section_index: u32 = 0, + atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, + + fn deinit(chunk: *SectionChunk, allocator: Allocator) void { + chunk.atoms.deinit(allocator); + } + + fn address(chunk: SectionChunk, elf_file: *Elf) i64 { + const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index]; + return @as(i64, @intCast(shdr.sh_addr)) + chunk.value; + } + + fn updateSize(chunk: *SectionChunk, object: *Object) void { + for (chunk.atoms.items) |atom_index| { + const atom_ptr = object.atom(atom_index).?; + assert(atom_ptr.alive); + const offset = atom_ptr.alignment.forward(chunk.size); + const padding = offset - chunk.size; + atom_ptr.value = @intCast(offset); + chunk.size += padding + atom_ptr.size; + chunk.alignment = chunk.alignment.max(atom_ptr.alignment); + } + } + + pub fn format( + chunk: SectionChunk, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = chunk; + _ = unused_fmt_string; + _ = options; + _ = writer; + @compileError("do not format SectionChunk directly"); + } + + const FormatCtx = struct { SectionChunk, *Elf }; + + pub fn fmt(chunk: SectionChunk, elf_file: *Elf) std.fmt.Formatter(format2) { + return .{ .data = .{ chunk, elf_file } }; + } + + fn format2( + ctx: FormatCtx, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = unused_fmt_string; + _ = options; + const chunk, const elf_file = ctx; + try writer.print("chunk : @{x} : shdr({d}) : align({x}) : size({x})", .{ + chunk.address(elf_file), chunk.output_section_index, + chunk.alignment.toByteUnits() orelse 0, chunk.size, + }); + try writer.writeAll(" : atoms{ "); + for (chunk.atoms.items, 0..) |atom_index, i| { + try writer.print("{d}", .{atom_index}); + if (i < chunk.atoms.items.len - 1) try writer.writeAll(", "); + } + try writer.writeAll(" }"); + } +}; + const Object = @This(); const std = @import("std"); From 45e46f0fb9f9f8a314802c544e92d1ee865119ef Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 1 Sep 2024 15:13:09 +0200 Subject: [PATCH 16/35] elf: allocate atom chunks using allocateChunk mechanics in objects --- src/link/Elf.zig | 50 ++++++++++++++++++------------------ src/link/Elf/Object.zig | 41 +++++++++++++++++------------ src/link/Elf/relocatable.zig | 1 - 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index cb5db6dec9..897deb86c5 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -727,7 +727,10 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen true; if (expand_section) { const needed_size = res.value + size; - try self.growAllocSection(shndx, needed_size); + if (shdr.sh_flags & elf.SHF_ALLOC != 0) + try self.growAllocSection(shndx, needed_size) + else + try self.growNonAllocSection(shndx, needed_size, @intCast(alignment.toByteUnits().?), true); } return res; @@ -1036,9 +1039,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod try self.setHashSections(); try self.setVersionSymtab(); - for (self.objects.items) |index| { - try self.file(index).?.object.addAtomsToOutputSections(self); - } try self.sortInitFini(); try self.updateMergeSectionSizes(); try self.updateSectionSizes(); @@ -3560,29 +3560,29 @@ fn updateSectionSizes(self: *Elf) !void { } const slice = self.sections.slice(); - for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { - if (atom_list.items.len == 0) continue; - if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; - for (atom_list.items) |ref| { - const atom_ptr = self.atom(ref) orelse continue; - if (!atom_ptr.alive) continue; - const offset = atom_ptr.alignment.forward(shdr.sh_size); - const padding = offset - shdr.sh_size; - atom_ptr.value = @intCast(offset); - shdr.sh_size += padding + atom_ptr.size; - shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); - } - } + // for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { + // if (atom_list.items.len == 0) continue; + // if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; + // for (atom_list.items) |ref| { + // const atom_ptr = self.atom(ref) orelse continue; + // if (!atom_ptr.alive) continue; + // const offset = atom_ptr.alignment.forward(shdr.sh_size); + // const padding = offset - shdr.sh_size; + // atom_ptr.value = @intCast(offset); + // shdr.sh_size += padding + atom_ptr.size; + // shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); + // } + // } - if (self.requiresThunks()) { - for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { - if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; - if (atom_list.items.len == 0) continue; + // if (self.requiresThunks()) { + // for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { + // if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; + // if (atom_list.items.len == 0) continue; - // Create jump/branch range extenders if needed. - try self.createThunks(shdr, @intCast(shndx)); - } - } + // // Create jump/branch range extenders if needed. + // try self.createThunks(shdr, @intCast(shndx)); + // } + // } const shdrs = slice.items(.shdr); if (self.eh_frame_section_index) |index| { diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 3337bfb1a2..26c2f2585b 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -955,27 +955,26 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void { } pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { - _ = elf_file; for (self.section_chunks.items) |*chunk| { chunk.updateSize(self); } -} -pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { - for (self.atoms_indexes.items) |atom_index| { - const atom_ptr = self.atom(atom_index) orelse continue; - if (!atom_ptr.alive) continue; - const shdr = atom_ptr.inputShdr(elf_file); - atom_ptr.output_section_index = elf_file.initOutputSection(.{ - .name = self.getString(shdr.sh_name), - .flags = shdr.sh_flags, - .type = shdr.sh_type, - }) catch unreachable; + for (self.section_chunks.items) |*chunk| { + const alloc_res = try elf_file.allocateChunk(chunk.output_section_index, chunk.size, chunk.alignment); + chunk.value = @intCast(alloc_res.value); - const comp = elf_file.base.comp; - const gpa = comp.gpa; - const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index]; - try atom_list.append(gpa, .{ .index = atom_index, .file = self.index }); + const slice = elf_file.sections.slice(); + const shdr = &slice.items(.shdr)[chunk.output_section_index]; + const last_atom_ref = &slice.items(.last_atom)[chunk.output_section_index]; + + const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom| + placement_atom.nextAtom(elf_file) == null + else + true; + if (expand_section) last_atom_ref.* = chunk.lastAtom(self).ref(); + shdr.sh_addralign = @max(shdr.sh_addralign, chunk.alignment.toByteUnits().?); + + // TODO create back and forward links } } @@ -1599,6 +1598,16 @@ const SectionChunk = struct { } } + fn firstAtom(chunk: SectionChunk, object: *Object) *Atom { + assert(chunk.atoms.items.len > 0); + return object.atom(chunk.atoms.items[0]).?; + } + + fn lastAtom(chunk: SectionChunk, object: *Object) *Atom { + assert(chunk.atoms.items.len > 0); + return object.atom(chunk.atoms.items[chunk.atoms.items.len - 1]).?; + } + pub fn format( chunk: SectionChunk, comptime unused_fmt_string: []const u8, diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 4397bc2ca3..71d28abb32 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -208,7 +208,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const } for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; - try object.addAtomsToOutputSections(elf_file); try object.addAtomsToRelaSections(elf_file); } try elf_file.updateMergeSectionSizes(); From 874ef6308e6e438985a141310b94028de33286dc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 2 Sep 2024 07:57:27 +0200 Subject: [PATCH 17/35] elf: do not create .eh_frame section if ZigObject already did so --- src/link/Dwarf.zig | 4 ++-- src/link/Elf.zig | 44 +++++++++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 97bc15ced8..bff33ecf14 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -391,9 +391,9 @@ pub const Section = struct { const atom = zo.symbol(sec.index).atom(elf_file).?; const shndx = atom.output_section_index; if (sec == &dwarf.debug_frame.section) - try elf_file.growAllocSection(shndx, len) + try elf_file.growAllocSection(shndx, len, sec.alignment.toByteUnits().?) else - try elf_file.growNonAllocSection(shndx, len, @intCast(sec.alignment.toByteUnits().?), true); + try elf_file.growNonAllocSection(shndx, len, sec.alignment.toByteUnits().?, true); const shdr = elf_file.sections.items(.shdr)[shndx]; atom.size = shdr.sh_size; atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 897deb86c5..bbacf8737c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -528,7 +528,7 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 { return start; } -pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { +pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void { const slice = self.sections.slice(); const shdr = &slice.items(.shdr)[shdr_index]; assert(shdr.sh_flags & elf.SHF_ALLOC != 0); @@ -547,8 +547,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { const existing_size = shdr.sh_size; shdr.sh_size = 0; // Must move the entire section. - const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign; - const new_offset = try self.findFreeSpace(needed_size, alignment); + const new_offset = try self.findFreeSpace(needed_size, min_alignment); log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ self.getShString(shdr.sh_name), @@ -588,7 +587,7 @@ pub fn growNonAllocSection( self: *Elf, shdr_index: u32, needed_size: u64, - min_alignment: u32, + min_alignment: u64, requires_file_copy: bool, ) !void { const shdr = &self.sections.items(.shdr)[shdr_index]; @@ -728,9 +727,9 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen if (expand_section) { const needed_size = res.value + size; if (shdr.sh_flags & elf.SHF_ALLOC != 0) - try self.growAllocSection(shndx, needed_size) + try self.growAllocSection(shndx, needed_size, alignment.toByteUnits().?) else - try self.growNonAllocSection(shndx, needed_size, @intCast(alignment.toByteUnits().?), true); + try self.growNonAllocSection(shndx, needed_size, alignment.toByteUnits().?, true); } return res; @@ -1831,8 +1830,8 @@ pub fn initOutputSection(self: *Elf, args: struct { break :blk args.name; }; const @"type" = tt: { - if (self.getTarget().cpu.arch == .x86_64 and - args.type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS; + if (self.getTarget().cpu.arch == .x86_64 and args.type == elf.SHT_X86_64_UNWIND) + break :tt elf.SHT_PROGBITS; switch (args.type) { elf.SHT_NULL => unreachable, elf.SHT_PROGBITS => { @@ -2896,21 +2895,28 @@ fn initSyntheticSections(self: *Elf) !void { const target = self.getTarget(); const ptr_size = self.ptrWidthBytes(); - const needs_eh_frame = for (self.objects.items) |index| { + const needs_eh_frame = if (self.zigObjectPtr()) |zo| + zo.eh_frame_index != null + else for (self.objects.items) |index| { if (self.file(index).?.object.cies.items.len > 0) break true; } else false; if (needs_eh_frame) { if (self.eh_frame_section_index == null) { - self.eh_frame_section_index = try self.addSection(.{ - .name = try self.insertShString(".eh_frame"), - .type = if (target.cpu.arch == .x86_64) - elf.SHT_X86_64_UNWIND - else - elf.SHT_PROGBITS, - .flags = elf.SHF_ALLOC, - .addralign = ptr_size, - .offset = std.math.maxInt(u64), - }); + self.eh_frame_section_index = blk: { + if (self.zigObjectPtr()) |zo| { + if (zo.eh_frame_index) |idx| break :blk zo.symbol(idx).atom(self).?.output_section_index; + } + break :blk try self.addSection(.{ + .name = try self.insertShString(".eh_frame"), + .type = if (target.cpu.arch == .x86_64) + elf.SHT_X86_64_UNWIND + else + elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC, + .addralign = ptr_size, + .offset = std.math.maxInt(u64), + }); + }; } if (comp.link_eh_frame_hdr) { self.eh_frame_hdr_section_index = try self.addSection(.{ From f87a7251a3f9ae7259c64f458823117370071943 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 2 Sep 2024 08:42:47 +0200 Subject: [PATCH 18/35] elf: actually write allocated atoms in object files --- src/link/Elf.zig | 102 ++-------------------------------------- src/link/Elf/Object.zig | 77 ++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 102 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index bbacf8737c..8963da645f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -4037,107 +4037,19 @@ fn allocateSpecialPhdrs(self: *Elf) void { } fn writeAtoms(self: *Elf) !void { - const gpa = self.base.comp.gpa; - - var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); - defer { - for (undefs.values()) |*refs| { - refs.deinit(); - } - undefs.deinit(); - } - - var has_reloc_errors = false; - const slice = self.sections.slice(); - for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { - if (shdr.sh_type == elf.SHT_NULL) continue; - if (shdr.sh_type == elf.SHT_NOBITS) continue; - if (atom_list.items.len == 0) continue; - - log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); - - // TODO really, really handle debug section separately - const base_offset = if (self.zigObjectPtr()) |zo| base_offset: { - for ([_]?Symbol.Index{ - zo.text_index, - zo.rodata_index, - zo.data_relro_index, - zo.data_index, - zo.tdata_index, - zo.eh_frame_index, - zo.debug_info_index, - zo.debug_abbrev_index, - zo.debug_aranges_index, - zo.debug_str_index, - zo.debug_line_index, - zo.debug_line_str_index, - zo.debug_loclists_index, - zo.debug_rnglists_index, - }) |maybe_sym_index| { - const sym_index = maybe_sym_index orelse continue; - const sym = zo.symbol(sym_index); - const atom_ptr = sym.atom(self).?; - if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size; - } - break :base_offset 0; - } else 0; - const sh_offset = shdr.sh_offset + base_offset; - const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; - - const buffer = try gpa.alloc(u8, sh_size); - defer gpa.free(buffer); - const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and - shdr.sh_flags & elf.SHF_EXECINSTR != 0 and self.getTarget().cpu.arch == .x86_64) - 0xcc // int3 - else - 0; - @memset(buffer, padding_byte); - - for (atom_list.items) |ref| { - const atom_ptr = self.atom(ref).?; - assert(atom_ptr.alive); - - const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse - return error.Overflow; - const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; - - log.debug("writing atom({}) at 0x{x}", .{ ref, sh_offset + offset }); - - // TODO decompress directly into provided buffer - const out_code = buffer[offset..][0..size]; - const in_code = switch (atom_ptr.file(self).?) { - .object => |x| try x.codeDecompressAlloc(self, ref.index), - .zig_object => |x| try x.codeAlloc(self, ref.index), - else => unreachable, - }; - defer gpa.free(in_code); - @memcpy(out_code, in_code); - - const res = if (shdr.sh_flags & elf.SHF_ALLOC == 0) - atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs) - else - atom_ptr.resolveRelocsAlloc(self, out_code); - _ = res catch |err| switch (err) { - error.UnsupportedCpuArch => { - try self.reportUnsupportedCpuArch(); - return error.FlushFailure; - }, - error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, - else => |e| return e, - }; - } - - try self.base.file.?.pwriteAll(buffer, sh_offset); + for (self.objects.items) |index| { + try self.file(index).?.object.writeAtoms(self); } if (self.requiresThunks()) { + const gpa = self.base.comp.gpa; var buffer = std.ArrayList(u8).init(gpa); defer buffer.deinit(); for (self.thunks.items) |th| { const thunk_size = th.size(self); try buffer.ensureUnusedCapacity(thunk_size); - const shdr = slice.items(.shdr)[th.output_section_index]; + const shdr = self.sections.items(.shdr)[th.output_section_index]; const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset; try th.write(self, buffer.writer()); assert(buffer.items.len == thunk_size); @@ -4145,10 +4057,6 @@ fn writeAtoms(self: *Elf) !void { buffer.clearRetainingCapacity(); } } - - try self.reportUndefinedSymbols(&undefs); - - if (has_reloc_errors) return error.FlushFailure; } pub fn updateSymtabSize(self: *Elf) !void { @@ -5089,7 +4997,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 { return off; } -fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { +pub fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { const gpa = self.base.comp.gpa; const max_notes = 4; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 26c2f2585b..590f7b6762 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -978,6 +978,68 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { } } +pub fn writeAtoms(self: *Object, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + + var undefs = std.AutoArrayHashMap(Elf.SymbolResolver.Index, std.ArrayList(Elf.Ref)).init(gpa); + defer { + for (undefs.values()) |*refs| { + refs.deinit(); + } + undefs.deinit(); + } + + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + + log.debug("writing atoms in {}", .{self.fmtPath()}); + + var has_reloc_errors = false; + for (self.section_chunks.items) |chunk| { + const osec = elf_file.sections.items(.shdr)[chunk.output_section_index]; + if (osec.sh_type == elf.SHT_NOBITS) continue; + + log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)}); + + try buffer.ensureUnusedCapacity(chunk.size); + buffer.appendNTimesAssumeCapacity(0, chunk.size); + + for (chunk.atoms.items) |atom_index| { + const atom_ptr = self.atom(atom_index).?; + assert(atom_ptr.alive); + + const offset = math.cast(usize, atom_ptr.value) orelse return error.Overflow; + const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; + + log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset }); + + const code = try self.codeDecompressAlloc(elf_file, atom_index); + defer gpa.free(code); + const out_code = buffer.items[offset..][0..size]; + @memcpy(out_code, code); + + const res = if (osec.sh_flags & elf.SHF_ALLOC == 0) + atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, &undefs) + else + atom_ptr.resolveRelocsAlloc(elf_file, out_code); + _ = res catch |err| switch (err) { + error.UnsupportedCpuArch => { + try elf_file.reportUnsupportedCpuArch(); + return error.FlushFailure; + }, + error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, + else => |e| return e, + }; + } + + try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file)); + buffer.clearRetainingCapacity(); + } + + try elf_file.reportUndefinedSymbols(&undefs); + if (has_reloc_errors) return error.FlushFailure; +} + pub fn initRelaSections(self: *Object, elf_file: *Elf) !void { for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; @@ -1544,12 +1606,12 @@ fn formatComdatGroups( } } -pub fn fmtPath(self: *Object) std.fmt.Formatter(formatPath) { +pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) { return .{ .data = self }; } fn formatPath( - object: *Object, + object: Object, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype, @@ -1586,13 +1648,18 @@ const SectionChunk = struct { return @as(i64, @intCast(shdr.sh_addr)) + chunk.value; } + fn offset(chunk: SectionChunk, elf_file: *Elf) u64 { + const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index]; + return shdr.sh_offset + @as(u64, @intCast(chunk.value)); + } + fn updateSize(chunk: *SectionChunk, object: *Object) void { for (chunk.atoms.items) |atom_index| { const atom_ptr = object.atom(atom_index).?; assert(atom_ptr.alive); - const offset = atom_ptr.alignment.forward(chunk.size); - const padding = offset - chunk.size; - atom_ptr.value = @intCast(offset); + const off = atom_ptr.alignment.forward(chunk.size); + const padding = off - chunk.size; + atom_ptr.value = @intCast(off); chunk.size += padding + atom_ptr.size; chunk.alignment = chunk.alignment.max(atom_ptr.alignment); } From 6a50a0f0ed3902b46afeda9c4a5b7f10cec60dba Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 2 Sep 2024 08:58:49 +0200 Subject: [PATCH 19/35] elf: update osec index for section chunks in objects --- src/link/Elf.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 8963da645f..752d0082c8 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3411,6 +3411,7 @@ fn shdrRank(self: *Elf, shndx: u32) u8 { return 0xf9; } }, + elf.SHT_X86_64_UNWIND => return 0xf0, elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7, elf.SHT_SYMTAB => return 0xfa, @@ -3503,6 +3504,12 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { } } + for (self.objects.items) |index| { + for (self.file(index).?.object.section_chunks.items) |*chunk| { + chunk.output_section_index = backlinks[chunk.output_section_index]; + } + } + for (self.comdat_group_sections.items) |*cg| { cg.shndx = backlinks[cg.shndx]; } From 6b53dc946117110907867ee67425585ae3729750 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 2 Sep 2024 09:08:37 +0200 Subject: [PATCH 20/35] elf: actually allocate atoms within each section chunk --- src/link/Elf.zig | 6 +++++- src/link/Elf/Object.zig | 8 +++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 752d0082c8..b6efa66247 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3505,8 +3505,12 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { } for (self.objects.items) |index| { - for (self.file(index).?.object.section_chunks.items) |*chunk| { + const object = self.file(index).?.object; + for (object.section_chunks.items) |*chunk| { chunk.output_section_index = backlinks[chunk.output_section_index]; + for (chunk.atoms.items) |atom_index| { + object.atom(atom_index).?.output_section_index = chunk.output_section_index; + } } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 590f7b6762..dd58727202 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -975,6 +975,12 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { shdr.sh_addralign = @max(shdr.sh_addralign, chunk.alignment.toByteUnits().?); // TODO create back and forward links + // TODO if we had a link from Atom to parent Chunk we would not need to update Atom's value or osec index + for (chunk.atoms.items) |atom_index| { + const atom_ptr = self.atom(atom_index).?; + atom_ptr.output_section_index = chunk.output_section_index; + atom_ptr.value += chunk.value; + } } } @@ -1008,7 +1014,7 @@ pub fn writeAtoms(self: *Object, elf_file: *Elf) !void { const atom_ptr = self.atom(atom_index).?; assert(atom_ptr.alive); - const offset = math.cast(usize, atom_ptr.value) orelse return error.Overflow; + const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow; const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset }); From 5cb51c10debd3e9542e35e22648bca2a8b59259e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 2 Sep 2024 11:42:47 +0200 Subject: [PATCH 21/35] elf: fix relocatable mode --- src/link/Elf.zig | 30 +++------- src/link/Elf/Object.zig | 39 ++++++++++++- src/link/Elf/ZigObject.zig | 2 +- src/link/Elf/eh_frame.zig | 2 +- src/link/Elf/relocatable.zig | 109 ++++++----------------------------- 5 files changed, 66 insertions(+), 116 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b6efa66247..cdc43b2d1a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3577,29 +3577,15 @@ fn updateSectionSizes(self: *Elf) !void { } const slice = self.sections.slice(); - // for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { - // if (atom_list.items.len == 0) continue; - // if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; - // for (atom_list.items) |ref| { - // const atom_ptr = self.atom(ref) orelse continue; - // if (!atom_ptr.alive) continue; - // const offset = atom_ptr.alignment.forward(shdr.sh_size); - // const padding = offset - shdr.sh_size; - // atom_ptr.value = @intCast(offset); - // shdr.sh_size += padding + atom_ptr.size; - // shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); - // } - // } + if (self.requiresThunks()) { + for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { + if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; + if (atom_list.items.len == 0) continue; - // if (self.requiresThunks()) { - // for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { - // if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; - // if (atom_list.items.len == 0) continue; - - // // Create jump/branch range extenders if needed. - // try self.createThunks(shdr, @intCast(shndx)); - // } - // } + // Create jump/branch range extenders if needed. + try self.createThunks(shdr, @intCast(shndx)); + } + } const shdrs = slice.items(.shdr); if (self.eh_frame_section_index) |index| { diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index dd58727202..92c8c1e23f 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -575,7 +575,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { } } -pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void { +pub fn claimUnresolvedRelocatable(self: *Object, elf_file: *Elf) void { const first_global = self.first_global orelse return; for (self.globals(), 0..) |*sym, i| { const esym_index = @as(u32, @intCast(first_global + i)); @@ -1046,6 +1046,43 @@ pub fn writeAtoms(self: *Object, elf_file: *Elf) !void { if (has_reloc_errors) return error.FlushFailure; } +pub fn writeAtomsRelocatable(self: *Object, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + + log.debug("writing atoms in {}", .{self.fmtPath()}); + + for (self.section_chunks.items) |chunk| { + const osec = elf_file.sections.items(.shdr)[chunk.output_section_index]; + if (osec.sh_type == elf.SHT_NOBITS) continue; + + log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)}); + + try buffer.ensureUnusedCapacity(chunk.size); + buffer.appendNTimesAssumeCapacity(0, chunk.size); + + for (chunk.atoms.items) |atom_index| { + const atom_ptr = self.atom(atom_index).?; + assert(atom_ptr.alive); + + const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow; + const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; + + log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset }); + + const code = try self.codeDecompressAlloc(elf_file, atom_index); + defer gpa.free(code); + const out_code = buffer.items[offset..][0..size]; + @memcpy(out_code, code); + } + + try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file)); + buffer.clearRetainingCapacity(); + } +} + pub fn initRelaSections(self: *Object, elf_file: *Elf) !void { for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 2d20895d2e..b62c0beae4 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -648,7 +648,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void { } } -pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { +pub fn claimUnresolvedRelocatable(self: ZigObject, elf_file: *Elf) void { for (self.global_symbols.items, 0..) |index, i| { const global = &self.symbols.items[index]; const esym = self.symtab.items(.elf_sym)[index]; diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index d660486010..8431a9e572 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -386,7 +386,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { if (has_reloc_errors) return error.RelocFailure; } -pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { +pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void { for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 71d28abb32..0ff2943ffa 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -40,7 +40,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co try zig_object.resolveSymbols(elf_file); try elf_file.addCommentString(); try elf_file.finalizeMergeSections(); - zig_object.claimUnresolvedObject(elf_file); + zig_object.claimUnresolvedRelocatable(elf_file); for (elf_file.merge_sections.items) |*msec| { if (msec.finalized_subsections.items.len == 0) continue; @@ -280,10 +280,10 @@ fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void { fn claimUnresolved(elf_file: *Elf) void { if (elf_file.zigObjectPtr()) |zig_object| { - zig_object.claimUnresolvedObject(elf_file); + zig_object.claimUnresolvedRelocatable(elf_file); } for (elf_file.objects.items) |index| { - elf_file.file(index).?.object.claimUnresolvedObject(elf_file); + elf_file.file(index).?.object.claimUnresolvedRelocatable(elf_file); } } @@ -349,29 +349,22 @@ fn initComdatGroups(elf_file: *Elf) !void { } fn updateSectionSizes(elf_file: *Elf) !void { + for (elf_file.objects.items) |index| { + try elf_file.file(index).?.object.allocateAtoms(elf_file); + } + const slice = elf_file.sections.slice(); for (slice.items(.shdr), 0..) |*shdr, shndx| { const atom_list = slice.items(.atom_list)[shndx]; - if (shdr.sh_type != elf.SHT_RELA) { - for (atom_list.items) |ref| { - const atom_ptr = elf_file.atom(ref) orelse continue; - if (!atom_ptr.alive) continue; - const offset = atom_ptr.alignment.forward(shdr.sh_size); - const padding = offset - shdr.sh_size; - atom_ptr.value = @intCast(offset); - shdr.sh_size += padding + atom_ptr.size; - shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); - } - } else { - for (atom_list.items) |ref| { - const atom_ptr = elf_file.atom(ref) orelse continue; - if (!atom_ptr.alive) continue; - const relocs = atom_ptr.relocs(elf_file); - shdr.sh_size += shdr.sh_entsize * relocs.len; - } - - if (shdr.sh_size == 0) shdr.sh_offset = 0; + if (shdr.sh_type != elf.SHT_RELA) continue; + for (atom_list.items) |ref| { + const atom_ptr = elf_file.atom(ref) orelse continue; + if (!atom_ptr.alive) continue; + const relocs = atom_ptr.relocs(elf_file); + shdr.sh_size += shdr.sh_entsize * relocs.len; } + + if (shdr.sh_size == 0) shdr.sh_offset = 0; } if (elf_file.eh_frame_section_index) |index| { @@ -422,74 +415,8 @@ fn allocateAllocSections(elf_file: *Elf) !void { } fn writeAtoms(elf_file: *Elf) !void { - const gpa = elf_file.base.comp.gpa; - const slice = elf_file.sections.slice(); - - // TODO iterate over `output_sections` directly - for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { - if (shdr.sh_type == elf.SHT_NULL) continue; - if (shdr.sh_type == elf.SHT_NOBITS) continue; - if (shdr.sh_type == elf.SHT_RELA) continue; - if (atom_list.items.len == 0) continue; - - log.debug("writing atoms in '{s}' section", .{elf_file.getShString(shdr.sh_name)}); - - // TODO really, really handle debug section separately - const base_offset = if (elf_file.zigObjectPtr()) |zo| blk: { - break :blk for ([_]?Symbol.Index{ - zo.debug_info_index, - zo.debug_abbrev_index, - zo.debug_aranges_index, - zo.debug_str_index, - zo.debug_line_index, - zo.debug_line_str_index, - zo.debug_loclists_index, - zo.debug_rnglists_index, - }) |maybe_sym_index| { - const sym_index = maybe_sym_index orelse continue; - const sym = zo.symbol(sym_index); - const atom_ptr = sym.atom(elf_file).?; - if (atom_ptr.output_section_index == shndx) break atom_ptr.size; - } else 0; - } else 0; - const sh_offset = shdr.sh_offset + base_offset; - const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; - - const buffer = try gpa.alloc(u8, sh_size); - defer gpa.free(buffer); - const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and - shdr.sh_flags & elf.SHF_EXECINSTR != 0) - 0xcc // int3 - else - 0; - @memset(buffer, padding_byte); - - for (atom_list.items) |ref| { - const atom_ptr = elf_file.atom(ref).?; - assert(atom_ptr.alive); - - const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse - return error.Overflow; - const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; - - log.debug("writing atom({}) from 0x{x} to 0x{x}", .{ - ref, - sh_offset + offset, - sh_offset + offset + size, - }); - - // TODO decompress directly into provided buffer - const out_code = buffer[offset..][0..size]; - const in_code = switch (atom_ptr.file(elf_file).?) { - .object => |x| try x.codeDecompressAlloc(elf_file, ref.index), - .zig_object => |x| try x.codeAlloc(elf_file, ref.index), - else => unreachable, - }; - defer gpa.free(in_code); - @memcpy(out_code, in_code); - } - - try elf_file.base.file.?.pwriteAll(buffer, sh_offset); + for (elf_file.objects.items) |index| { + try elf_file.file(index).?.object.writeAtomsRelocatable(elf_file); } } @@ -541,7 +468,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size)); defer buffer.deinit(); - try eh_frame.writeEhFrameObject(elf_file, buffer.writer()); + try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer()); log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ shdr.sh_offset + existing_size, shdr.sh_offset + sh_size, From 2ef3e30e2d04f16510d0953e6d266a97bcb4eb49 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Sep 2024 13:28:01 +0200 Subject: [PATCH 22/35] elf: emit relocs for self-hosted generated .eh_frame section --- src/link/Elf.zig | 24 +++++++++++++----------- src/link/Elf/Object.zig | 28 +++++++++++++++++++--------- src/link/Elf/ZigObject.zig | 1 + src/link/Elf/eh_frame.zig | 30 ++++++++++++++++++++++++++---- src/link/Elf/relocatable.zig | 3 ++- 5 files changed, 61 insertions(+), 25 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index cdc43b2d1a..d660c48b4b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3388,34 +3388,36 @@ fn shdrRank(self: *Elf, shndx: u32) u8 { elf.SHT_PREINIT_ARRAY, elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY, - => return 0xf2, + => return 0xf1, - elf.SHT_DYNAMIC => return 0xf3, + elf.SHT_DYNAMIC => return 0xf2, elf.SHT_RELA, elf.SHT_GROUP => return 0xf, elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { if (flags & elf.SHF_EXECINSTR != 0) { - return 0xf1; + return 0xf0; } else if (flags & elf.SHF_WRITE != 0) { - return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6; + return if (flags & elf.SHF_TLS != 0) 0xf3 else 0xf5; } else if (mem.eql(u8, name, ".interp")) { return 1; + } else if (mem.startsWith(u8, name, ".eh_frame")) { + return 0xe1; } else { - return 0xf0; + return 0xe0; } } else { if (mem.startsWith(u8, name, ".debug")) { - return 0xf8; + return 0xf7; } else { - return 0xf9; + return 0xf8; } }, - elf.SHT_X86_64_UNWIND => return 0xf0, + elf.SHT_X86_64_UNWIND => return 0xe1, - elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7, - elf.SHT_SYMTAB => return 0xfa, - elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb, + elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6, + elf.SHT_SYMTAB => return 0xf9, + elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfa, else => return 0xff, } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 92c8c1e23f..a72ac697dd 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -391,15 +391,24 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: .input_section_index = shndx, .file_index = self.index, }), - .fde => try self.fdes.append(allocator, .{ - .offset = data_start + rec.offset, - .size = rec.size, - .cie_index = undefined, - .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), - .rel_num = @as(u32, @intCast(rel_range.len)), - .input_section_index = shndx, - .file_index = self.index, - }), + .fde => { + if (rel_range.len == 0) { + // No relocs for an FDE means we cannot associate this FDE to an Atom + // so we skip it. According to mold source code + // (https://github.com/rui314/mold/blob/a3e69502b0eaf1126d6093e8ea5e6fdb95219811/src/input-files.cc#L525-L528) + // this can happen for object files built with -r flag by the linker. + continue; + } + try self.fdes.append(allocator, .{ + .offset = data_start + rec.offset, + .size = rec.size, + .cie_index = undefined, + .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), + .rel_num = @as(u32, @intCast(rel_range.len)), + .input_section_index = shndx, + .file_index = self.index, + }); + }, } } @@ -1106,6 +1115,7 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void { for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; + if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; const shndx = blk: { const shndx = atom_ptr.relocsShndx() orelse continue; const shdr = self.shdrs.items[shndx]; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index b62c0beae4..6d2325fb7e 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -808,6 +808,7 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; + if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; const rela_shndx = atom_ptr.relocsShndx() orelse continue; // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level if (self.relocs.items[rela_shndx].items.len == 0) continue; diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 8431a9e572..54024fa1bb 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -288,6 +288,13 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { pub fn calcEhFrameRelocs(elf_file: *Elf) usize { var count: usize = 0; + if (elf_file.zigObjectPtr()) |zo| zo: { + const sym_index = zo.eh_frame_index orelse break :zo; + const sym = zo.symbol(sym_index); + const atom_ptr = zo.atom(sym.ref.index).?; + if (!atom_ptr.alive) break :zo; + count += atom_ptr.relocs(elf_file).len; + } for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; for (object.cies.items) |cie| { @@ -416,9 +423,9 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void { } } -fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { +fn emitReloc(elf_file: *Elf, base_offset: u64, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { const cpu_arch = elf_file.getTarget().cpu.arch; - const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset; + const r_offset = base_offset + rel.r_offset; const r_type = rel.r_type(); var r_addend = rel.r_addend; var r_sym: u32 = 0; @@ -452,6 +459,19 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { elf_file.sections.items(.shdr)[elf_file.eh_frame_section_index.?].sh_addr, }); + if (elf_file.zigObjectPtr()) |zo| zo: { + const sym_index = zo.eh_frame_index orelse break :zo; + const sym = zo.symbol(sym_index); + const atom_ptr = zo.atom(sym.ref.index).?; + if (!atom_ptr.alive) break :zo; + for (atom_ptr.relocs(elf_file)) |rel| { + const ref = zo.resolveSymbol(rel.r_sym(), elf_file); + const target = elf_file.symbol(ref).?; + const out_rel = emitReloc(elf_file, 0, target, rel); + try writer.writeStruct(out_rel); + } + } + for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; @@ -460,7 +480,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (cie.relocs(elf_file)) |rel| { const ref = object.resolveSymbol(rel.r_sym(), elf_file); const sym = elf_file.symbol(ref).?; - const out_rel = emitReloc(elf_file, cie, sym, rel); + const offset = cie.address(elf_file) - cie.offset; + const out_rel = emitReloc(elf_file, offset, sym, rel); try writer.writeStruct(out_rel); } } @@ -470,7 +491,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (fde.relocs(elf_file)) |rel| { const ref = object.resolveSymbol(rel.r_sym(), elf_file); const sym = elf_file.symbol(ref).?; - const out_rel = emitReloc(elf_file, fde, sym, rel); + const offset = fde.address(elf_file) - fde.offset; + const out_rel = emitReloc(elf_file, offset, sym, rel); try writer.writeStruct(out_rel); } } diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 0ff2943ffa..b4a7f08f6e 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -424,8 +424,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; const slice = elf_file.sections.slice(); - for (slice.items(.shdr), slice.items(.atom_list)) |shdr, atom_list| { + for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { if (shdr.sh_type != elf.SHT_RELA) continue; + if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_rela_section_index) continue; if (atom_list.items.len == 0) continue; const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse From 88e0d49febf5839654e4a5f3dc02ad6b2a82e242 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Sep 2024 13:49:14 +0200 Subject: [PATCH 23/35] elf: init rela sections in a separate pass for ZigObject --- src/link/Elf/ZigObject.zig | 26 ++++++++++++++++++++++---- src/link/Elf/relocatable.zig | 3 +++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 6d2325fb7e..8eef1a84e4 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -803,6 +803,27 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { try writer.writeAll(self.data.items); } +pub fn initRelaSections(self: *ZigObject, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + for (self.atoms_indexes.items) |atom_index| { + const atom_ptr = self.atom(atom_index) orelse continue; + if (!atom_ptr.alive) continue; + if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; + const rela_shndx = atom_ptr.relocsShndx() orelse continue; + // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level + if (self.relocs.items[rela_shndx].items.len == 0) continue; + const out_shndx = atom_ptr.output_section_index; + const out_shdr = elf_file.sections.items(.shdr)[out_shndx]; + if (out_shdr.sh_type == elf.SHT_NOBITS) continue; + const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{ + elf_file.getShString(out_shdr.sh_name), + }); + defer gpa.free(rela_sect_name); + _ = elf_file.sectionByName(rela_sect_name) orelse + try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), out_shndx); + } +} + pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; for (self.atoms_indexes.items) |atom_index| { @@ -819,10 +840,7 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { elf_file.getShString(out_shdr.sh_name), }); defer gpa.free(rela_sect_name); - const out_rela_shndx = if (elf_file.sectionByName(rela_sect_name)) |out_rela_shndx| - out_rela_shndx - else - try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), out_shndx); + const out_rela_shndx = elf_file.sectionByName(rela_sect_name).?; const out_rela_shdr = &elf_file.sections.items(.shdr)[out_rela_shndx]; out_rela_shdr.sh_info = out_shndx; out_rela_shdr.sh_link = elf_file.symtab_section_index.?; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index b4a7f08f6e..6499bc207b 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -288,6 +288,9 @@ fn claimUnresolved(elf_file: *Elf) void { } fn initSections(elf_file: *Elf) !void { + if (elf_file.zigObjectPtr()) |zo| { + try zo.initRelaSections(elf_file); + } for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; try object.initOutputSections(elf_file); From 5cdad186fe1cb83c6d79642433bfbe330436914a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Sep 2024 14:45:59 +0200 Subject: [PATCH 24/35] elf: do not create .eh_frame section if ZigObject already did so in relocatable mode --- src/link/Elf/relocatable.zig | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 6499bc207b..ea710e7b2a 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -302,21 +302,28 @@ fn initSections(elf_file: *Elf) !void { try msec.initOutputSection(elf_file); } - const needs_eh_frame = for (elf_file.objects.items) |index| { + const needs_eh_frame = if (elf_file.zigObjectPtr()) |zo| + zo.eh_frame_index != null + else for (elf_file.objects.items) |index| { if (elf_file.file(index).?.object.cies.items.len > 0) break true; } else false; if (needs_eh_frame) { if (elf_file.eh_frame_section_index == null) { - elf_file.eh_frame_section_index = try elf_file.addSection(.{ - .name = try elf_file.insertShString(".eh_frame"), - .type = if (elf_file.getTarget().cpu.arch == .x86_64) - elf.SHT_X86_64_UNWIND - else - elf.SHT_PROGBITS, - .flags = elf.SHF_ALLOC, - .addralign = elf_file.ptrWidthBytes(), - .offset = std.math.maxInt(u64), - }); + elf_file.eh_frame_section_index = blk: { + if (elf_file.zigObjectPtr()) |zo| { + if (zo.eh_frame_index) |idx| break :blk zo.symbol(idx).atom(elf_file).?.output_section_index; + } + break :blk try elf_file.addSection(.{ + .name = try elf_file.insertShString(".eh_frame"), + .type = if (elf_file.getTarget().cpu.arch == .x86_64) + elf.SHT_X86_64_UNWIND + else + elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC, + .addralign = elf_file.ptrWidthBytes(), + .offset = std.math.maxInt(u64), + }); + }; } elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr( try elf_file.insertShString(".rela.eh_frame"), From fca92fd7c0a2e1431338ef62440751870563a0e3 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Sep 2024 15:07:30 +0200 Subject: [PATCH 25/35] elf: copy existing data when allocating other alloc sections in relocatable mode --- src/link/Elf/relocatable.zig | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index ea710e7b2a..e66ae99ad2 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -407,7 +407,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void { /// Allocates alloc sections when merging relocatable objects files together. fn allocateAllocSections(elf_file: *Elf) !void { - for (elf_file.sections.items(.shdr)) |*shdr| { + for (elf_file.sections.items(.shdr), 0..) |*shdr, shndx| { if (shdr.sh_type == elf.SHT_NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; if (shdr.sh_type == elf.SHT_NOBITS) { @@ -418,6 +418,34 @@ fn allocateAllocSections(elf_file: *Elf) !void { if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) { shdr.sh_size = 0; const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign); + + if (elf_file.zigObjectPtr()) |zo| blk: { + const existing_size = for ([_]?Symbol.Index{ + zo.text_index, + zo.rodata_index, + zo.data_relro_index, + zo.data_index, + zo.tdata_index, + zo.eh_frame_index, + }) |maybe_sym_index| { + const sect_sym_index = maybe_sym_index orelse continue; + const sect_atom_ptr = zo.symbol(sect_sym_index).atom(elf_file).?; + if (sect_atom_ptr.output_section_index == shndx) break sect_atom_ptr.size; + } else break :blk; + log.debug("moving {s} from 0x{x} to 0x{x}", .{ + elf_file.getShString(shdr.sh_name), + shdr.sh_offset, + new_offset, + }); + const amt = try elf_file.base.file.?.copyRangeAll( + shdr.sh_offset, + elf_file.base.file.?, + new_offset, + existing_size, + ); + if (amt != existing_size) return error.InputOutput; + } + shdr.sh_offset = new_offset; shdr.sh_size = needed_size; } From eeec50d2515c5a3b65cab697ba3e28d89cc3b14c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Sep 2024 21:01:12 +0200 Subject: [PATCH 26/35] elf: misc .eh_frame management fixes --- src/link/Elf.zig | 44 +++++++++++++------------------ src/link/Elf/Object.zig | 1 + src/link/Elf/ZigObject.zig | 12 +++++++++ src/link/Elf/eh_frame.zig | 18 +++++++------ src/link/Elf/relocatable.zig | 50 +++++++++++++++++------------------- 5 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d660c48b4b..99ba66e92d 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -621,7 +621,6 @@ pub fn growNonAllocSection( try self.base.file.?.setEndPos(shdr.sh_offset + needed_size); } shdr.sh_size = needed_size; - self.markDirty(shdr_index); } @@ -2895,28 +2894,25 @@ fn initSyntheticSections(self: *Elf) !void { const target = self.getTarget(); const ptr_size = self.ptrWidthBytes(); - const needs_eh_frame = if (self.zigObjectPtr()) |zo| - zo.eh_frame_index != null - else for (self.objects.items) |index| { - if (self.file(index).?.object.cies.items.len > 0) break true; - } else false; + const needs_eh_frame = blk: { + if (self.zigObjectPtr()) |zo| + if (zo.eh_frame_index != null) break :blk true; + break :blk for (self.objects.items) |index| { + if (self.file(index).?.object.cies.items.len > 0) break true; + } else false; + }; if (needs_eh_frame) { if (self.eh_frame_section_index == null) { - self.eh_frame_section_index = blk: { - if (self.zigObjectPtr()) |zo| { - if (zo.eh_frame_index) |idx| break :blk zo.symbol(idx).atom(self).?.output_section_index; - } - break :blk try self.addSection(.{ - .name = try self.insertShString(".eh_frame"), - .type = if (target.cpu.arch == .x86_64) - elf.SHT_X86_64_UNWIND - else - elf.SHT_PROGBITS, - .flags = elf.SHF_ALLOC, - .addralign = ptr_size, - .offset = std.math.maxInt(u64), - }); - }; + self.eh_frame_section_index = self.sectionByName(".eh_frame") orelse try self.addSection(.{ + .name = try self.insertShString(".eh_frame"), + .type = if (target.cpu.arch == .x86_64) + elf.SHT_X86_64_UNWIND + else + elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC, + .addralign = ptr_size, + .offset = std.math.maxInt(u64), + }); } if (comp.link_eh_frame_hdr) { self.eh_frame_hdr_section_index = try self.addSection(.{ @@ -3591,11 +3587,7 @@ fn updateSectionSizes(self: *Elf) !void { const shdrs = slice.items(.shdr); if (self.eh_frame_section_index) |index| { - shdrs[index].sh_size = existing_size: { - const zo = self.zigObjectPtr() orelse break :existing_size 0; - const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); - break :existing_size sym.atom(self).?.size; - } + try eh_frame.calcEhFrameSize(self); + shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self); } if (self.eh_frame_hdr_section_index) |index| { diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index a72ac697dd..884826d82b 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -1096,6 +1096,7 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void { for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; + if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; const shndx = atom_ptr.relocsShndx() orelse continue; const shdr = self.shdrs.items[shndx]; const out_shndx = try elf_file.initOutputSection(.{ diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 8eef1a84e4..416ed06126 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -111,6 +111,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_str_section_dirty = true; self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_str_index.?).ref; } if (self.debug_info_index == null) { @@ -121,6 +122,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_info_section_dirty = true; self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_info_index.?).ref; } if (self.debug_abbrev_index == null) { @@ -131,6 +133,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_abbrev_section_dirty = true; self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_abbrev_index.?).ref; } if (self.debug_aranges_index == null) { @@ -141,6 +144,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_aranges_section_dirty = true; self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_aranges_index.?).ref; } if (self.debug_line_index == null) { @@ -151,6 +155,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_line_section_dirty = true; self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_index.?).ref; } if (self.debug_line_str_index == null) { @@ -163,6 +168,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_line_str_section_dirty = true; self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_str_index.?).ref; } if (self.debug_loclists_index == null) { @@ -173,6 +179,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_loclists_section_dirty = true; self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_loclists_index.?).ref; } if (self.debug_rnglists_index == null) { @@ -183,6 +190,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.debug_rnglists_section_dirty = true; self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_rnglists_index.?).ref; } if (self.eh_frame_index == null) { @@ -197,6 +205,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { }); self.eh_frame_section_dirty = true; self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec); + elf_file.sections.items(.last_atom)[osec] = self.symbol(self.eh_frame_index.?).ref; } try dwarf.initMetadata(); @@ -1116,6 +1125,9 @@ pub fn getOrCreateMetadataForNav( return gop.value_ptr.symbol_index; } +// FIXME: we always create an atom to basically store size and alignment, however, this is only true for +// sections that have a single atom like the debug sections. It would be a better solution to decouple this +// concept from the atom, maybe. fn addSectionSymbol( self: *ZigObject, allocator: Allocator, diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 54024fa1bb..a9e3e618cb 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -233,7 +233,10 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { const comp = elf_file.base.comp; const gpa = comp.gpa; - var offset: usize = 0; + var offset: usize = if (elf_file.zigObjectPtr()) |zo| blk: { + const sym = zo.symbol(zo.eh_frame_index orelse break :blk 0); + break :blk sym.atom(elf_file).?.size; + } else 0; var cies = std.ArrayList(Cie).init(gpa); defer cies.deinit(); @@ -423,9 +426,8 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void { } } -fn emitReloc(elf_file: *Elf, base_offset: u64, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { +fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { const cpu_arch = elf_file.getTarget().cpu.arch; - const r_offset = base_offset + rel.r_offset; const r_type = rel.r_type(); var r_addend = rel.r_addend; var r_sym: u32 = 0; @@ -467,7 +469,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (atom_ptr.relocs(elf_file)) |rel| { const ref = zo.resolveSymbol(rel.r_sym(), elf_file); const target = elf_file.symbol(ref).?; - const out_rel = emitReloc(elf_file, 0, target, rel); + const out_rel = emitReloc(elf_file, rel.r_offset, target, rel); try writer.writeStruct(out_rel); } } @@ -480,8 +482,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (cie.relocs(elf_file)) |rel| { const ref = object.resolveSymbol(rel.r_sym(), elf_file); const sym = elf_file.symbol(ref).?; - const offset = cie.address(elf_file) - cie.offset; - const out_rel = emitReloc(elf_file, offset, sym, rel); + const r_offset = cie.address(elf_file) + rel.r_offset - cie.offset; + const out_rel = emitReloc(elf_file, r_offset, sym, rel); try writer.writeStruct(out_rel); } } @@ -491,8 +493,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { for (fde.relocs(elf_file)) |rel| { const ref = object.resolveSymbol(rel.r_sym(), elf_file); const sym = elf_file.symbol(ref).?; - const offset = fde.address(elf_file) - fde.offset; - const out_rel = emitReloc(elf_file, offset, sym, rel); + const r_offset = fde.address(elf_file) + rel.r_offset - fde.offset; + const out_rel = emitReloc(elf_file, r_offset, sym, rel); try writer.writeStruct(out_rel); } } diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index e66ae99ad2..9182c06946 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -302,30 +302,29 @@ fn initSections(elf_file: *Elf) !void { try msec.initOutputSection(elf_file); } - const needs_eh_frame = if (elf_file.zigObjectPtr()) |zo| - zo.eh_frame_index != null - else for (elf_file.objects.items) |index| { - if (elf_file.file(index).?.object.cies.items.len > 0) break true; - } else false; + const needs_eh_frame = blk: { + if (elf_file.zigObjectPtr()) |zo| + if (zo.eh_frame_index != null) break :blk true; + break :blk for (elf_file.objects.items) |index| { + if (elf_file.file(index).?.object.cies.items.len > 0) break true; + } else false; + }; if (needs_eh_frame) { if (elf_file.eh_frame_section_index == null) { - elf_file.eh_frame_section_index = blk: { - if (elf_file.zigObjectPtr()) |zo| { - if (zo.eh_frame_index) |idx| break :blk zo.symbol(idx).atom(elf_file).?.output_section_index; - } - break :blk try elf_file.addSection(.{ - .name = try elf_file.insertShString(".eh_frame"), - .type = if (elf_file.getTarget().cpu.arch == .x86_64) - elf.SHT_X86_64_UNWIND - else - elf.SHT_PROGBITS, - .flags = elf.SHF_ALLOC, - .addralign = elf_file.ptrWidthBytes(), - .offset = std.math.maxInt(u64), - }); - }; + elf_file.eh_frame_section_index = elf_file.sectionByName(".eh_frame") orelse + try elf_file.addSection(.{ + .name = try elf_file.insertShString(".eh_frame"), + .type = if (elf_file.getTarget().cpu.arch == .x86_64) + elf.SHT_X86_64_UNWIND + else + elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC, + .addralign = elf_file.ptrWidthBytes(), + .offset = std.math.maxInt(u64), + }); } - elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr( + elf_file.eh_frame_rela_section_index = elf_file.sectionByName(".rela.eh_frame") orelse + try elf_file.addRelaShdr( try elf_file.insertShString(".rela.eh_frame"), elf_file.eh_frame_section_index.?, ); @@ -367,6 +366,7 @@ fn updateSectionSizes(elf_file: *Elf) !void { for (slice.items(.shdr), 0..) |*shdr, shndx| { const atom_list = slice.items(.atom_list)[shndx]; if (shdr.sh_type != elf.SHT_RELA) continue; + if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue; for (atom_list.items) |ref| { const atom_ptr = elf_file.atom(ref) orelse continue; if (!atom_ptr.alive) continue; @@ -378,11 +378,7 @@ fn updateSectionSizes(elf_file: *Elf) !void { } if (elf_file.eh_frame_section_index) |index| { - slice.items(.shdr)[index].sh_size = existing_size: { - const zo = elf_file.zigObjectPtr() orelse break :existing_size 0; - const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); - break :existing_size sym.atom(elf_file).?.size; - } + try eh_frame.calcEhFrameSize(elf_file); + slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file); } if (elf_file.eh_frame_rela_section_index) |index| { const shdr = &slice.items(.shdr)[index]; @@ -464,8 +460,8 @@ fn writeSyntheticSections(elf_file: *Elf) !void { for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { if (shdr.sh_type != elf.SHT_RELA) continue; - if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_rela_section_index) continue; if (atom_list.items.len == 0) continue; + if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue; const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse return error.Overflow; From 801f038c2ced9c0d7147f4304834ac6ae68e4cb0 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 06:43:33 +0200 Subject: [PATCH 27/35] elf: do not pad placeholders coming from input object files This is currently not entirely accurate since no padding will affect the last-most atom of ZigObject that should be padded. --- src/link/Elf.zig | 33 +++++++++++++++++++-------------- src/link/Elf/Object.zig | 7 ++++++- src/link/Elf/ZigObject.zig | 6 +++++- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 99ba66e92d..12f564edcf 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -659,12 +659,17 @@ const AllocateChunkResult = struct { placement: Ref, }; -pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignment) !AllocateChunkResult { +pub fn allocateChunk(self: *Elf, args: struct { + size: u64, + shndx: u32, + alignment: Atom.Alignment, + requires_padding: bool = true, +}) !AllocateChunkResult { const slice = self.sections.slice(); - const shdr = &slice.items(.shdr)[shndx]; - const free_list = &slice.items(.free_list)[shndx]; - const last_atom_ref = &slice.items(.last_atom)[shndx]; - const new_atom_ideal_capacity = padToIdeal(size); + const shdr = &slice.items(.shdr)[args.shndx]; + const free_list = &slice.items(.free_list)[args.shndx]; + const last_atom_ref = &slice.items(.last_atom)[args.shndx]; + const new_atom_ideal_capacity = if (args.requires_padding) padToIdeal(args.size) else args.size; // First we look for an appropriately sized free list node. // The list is unordered. We'll just take the first thing that works. @@ -676,11 +681,11 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen // We now have a pointer to a live atom that has too much capacity. // Is it enough that we could fit this new atom? const cap = big_atom.capacity(self); - const ideal_capacity = padToIdeal(cap); + const ideal_capacity = if (args.requires_padding) padToIdeal(cap) else cap; const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; - const new_start_vaddr = alignment.backward(new_start_vaddr_unaligned); + const new_start_vaddr = args.alignment.backward(new_start_vaddr_unaligned); if (new_start_vaddr < ideal_capacity_end_vaddr) { // Additional bookkeeping here to notice if this free list node // should be deleted because the block that it points to has grown to take up @@ -703,9 +708,9 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen } break :blk .{ .value = new_start_vaddr, .placement = big_atom_ref }; } else if (self.atom(last_atom_ref.*)) |last_atom| { - const ideal_capacity = padToIdeal(last_atom.size); + const ideal_capacity = if (args.requires_padding) padToIdeal(last_atom.size) else last_atom.size; const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity; - const new_start_vaddr = alignment.forward(ideal_capacity_end_vaddr); + const new_start_vaddr = args.alignment.forward(ideal_capacity_end_vaddr); break :blk .{ .value = new_start_vaddr, .placement = last_atom.ref() }; } else { break :blk .{ .value = 0, .placement = .{} }; @@ -713,8 +718,8 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen }; log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{ - size, - alignment.toByteUnits().?, + args.size, + args.alignment.toByteUnits().?, shdr.sh_addr + res.value, shdr.sh_offset + res.value, }); @@ -724,11 +729,11 @@ pub fn allocateChunk(self: *Elf, shndx: u32, size: u64, alignment: Atom.Alignmen else true; if (expand_section) { - const needed_size = res.value + size; + const needed_size = res.value + args.size; if (shdr.sh_flags & elf.SHF_ALLOC != 0) - try self.growAllocSection(shndx, needed_size, alignment.toByteUnits().?) + try self.growAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?) else - try self.growNonAllocSection(shndx, needed_size, alignment.toByteUnits().?, true); + try self.growNonAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?, true); } return res; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 884826d82b..4a1ca685c5 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -969,7 +969,12 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { } for (self.section_chunks.items) |*chunk| { - const alloc_res = try elf_file.allocateChunk(chunk.output_section_index, chunk.size, chunk.alignment); + const alloc_res = try elf_file.allocateChunk(.{ + .shndx = chunk.output_section_index, + .size = chunk.size, + .alignment = chunk.alignment, + .requires_padding = false, + }); chunk.value = @intCast(alloc_res.value); const slice = elf_file.sections.slice(); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 416ed06126..0dc4bd9dae 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1996,7 +1996,11 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { } fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { - const alloc_res = try elf_file.allocateChunk(atom_ptr.output_section_index, atom_ptr.size, atom_ptr.alignment); + const alloc_res = try elf_file.allocateChunk(.{ + .shndx = atom_ptr.output_section_index, + .size = atom_ptr.size, + .alignment = atom_ptr.alignment, + }); atom_ptr.value = @intCast(alloc_res.value); const slice = elf_file.sections.slice(); From 8c76a61ef541cf285a82fcc928face4082606c03 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 06:46:57 +0200 Subject: [PATCH 28/35] test/link/elf: test --gc-sections on Zig input with LLVM too --- test/link/elf.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/test/link/elf.zig b/test/link/elf.zig index 159703bbb3..34bc4bb128 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -66,6 +66,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target })); elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target })); elf_step.dependOn(testGcSections(b, .{ .target = musl_target })); + elf_step.dependOn(testGcSectionsZig(b, .{ .target = musl_target })); elf_step.dependOn(testImageBase(b, .{ .target = musl_target })); elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target })); elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target })); From 6ec8b15918dcd692f88875843a51a0514e315d9d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 07:19:25 +0200 Subject: [PATCH 29/35] elf: fix emitting static lib when ZigObject is present --- src/link/Elf/relocatable.zig | 21 ++++++++------------- test/link/elf.zig | 1 + 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 9182c06946..5df6bb9946 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -18,7 +18,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co } for (positionals.items) |obj| { - parsePositional(elf_file, obj.path) catch |err| switch (err) { + parsePositionalStaticLib(elf_file, obj.path) catch |err| switch (err) { error.MalformedObject, error.MalformedArchive, error.InvalidMachineType, @@ -38,17 +38,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co // First, we flush relocatable object file generated with our backends. if (elf_file.zigObjectPtr()) |zig_object| { try zig_object.resolveSymbols(elf_file); + elf_file.markEhFrameAtomsDead(); try elf_file.addCommentString(); try elf_file.finalizeMergeSections(); zig_object.claimUnresolvedRelocatable(elf_file); - for (elf_file.merge_sections.items) |*msec| { - if (msec.finalized_subsections.items.len == 0) continue; - try msec.initOutputSection(elf_file); - } - - try elf_file.initSymtab(); - try elf_file.initShStrtab(); + try initSections(elf_file); try elf_file.sortShdrs(); try zig_object.addAtomsToRelaSections(elf_file); try elf_file.updateMergeSectionSizes(); @@ -229,17 +224,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const if (elf_file.base.hasErrors()) return error.FlushFailure; } -fn parsePositional(elf_file: *Elf, path: []const u8) Elf.ParseError!void { +fn parsePositionalStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { if (try Object.isObject(path)) { - try parseObject(elf_file, path); + try parseObjectStaticLib(elf_file, path); } else if (try Archive.isArchive(path)) { - try parseArchive(elf_file, path); + try parseArchiveStaticLib(elf_file, path); } else return error.UnknownFileType; // TODO: should we check for LD script? // Actually, should we even unpack an archive? } -fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void { +fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { const gpa = elf_file.base.comp.gpa; const handle = try std.fs.cwd().openFile(path, .{}); const fh = try elf_file.addFileHandle(handle); @@ -256,7 +251,7 @@ fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void { try object.parseAr(elf_file); } -fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void { +fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { const gpa = elf_file.base.comp.gpa; const handle = try std.fs.cwd().openFile(path, .{}); const fh = try elf_file.addFileHandle(handle); diff --git a/test/link/elf.zig b/test/link/elf.zig index 34bc4bb128..9d169faf1d 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -55,6 +55,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { // Exercise linker in ar mode elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target })); + elf_step.dependOn(testEmitStaticLibZig(b, .{ .target = musl_target })); // Exercise linker with LLVM backend // musl tests From 64ad6eff16aac1f6154efa12406818efed57bf73 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 08:10:19 +0200 Subject: [PATCH 30/35] elf: create back/forward links for atoms within section chunks --- src/link/Elf/Object.zig | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 4a1ca685c5..0d063927ce 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -988,7 +988,25 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { if (expand_section) last_atom_ref.* = chunk.lastAtom(self).ref(); shdr.sh_addralign = @max(shdr.sh_addralign, chunk.alignment.toByteUnits().?); - // TODO create back and forward links + { + var idx: usize = 0; + while (idx < chunk.atoms.items.len) : (idx += 1) { + const curr_atom_ptr = self.atom(chunk.atoms.items[idx]).?; + if (idx > 0) { + curr_atom_ptr.prev_atom_ref = .{ .index = chunk.atoms.items[idx - 1], .file = self.index }; + } + if (idx + 1 < chunk.atoms.items.len) { + curr_atom_ptr.next_atom_ref = .{ .index = chunk.atoms.items[idx + 1], .file = self.index }; + } + } + } + + if (elf_file.atom(alloc_res.placement)) |placement_atom| { + chunk.firstAtom(self).prev_atom_ref = placement_atom.ref(); + chunk.lastAtom(self).next_atom_ref = placement_atom.next_atom_ref; + placement_atom.next_atom_ref = chunk.firstAtom(self).ref(); + } + // TODO if we had a link from Atom to parent Chunk we would not need to update Atom's value or osec index for (chunk.atoms.items) |atom_index| { const atom_ptr = self.atom(atom_index).?; From d302a1068effe4edcd36bd01f77ac2e1b1048e16 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 11:40:56 +0200 Subject: [PATCH 31/35] elf: rename SectionChunk into AtomList and store as part of Section --- src/link/Elf.zig | 133 ++++++++++------- src/link/Elf/Object.zig | 276 +---------------------------------- src/link/Elf/relocatable.zig | 20 ++- 3 files changed, 103 insertions(+), 326 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 12f564edcf..67969b7fb7 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -393,7 +393,8 @@ pub fn deinit(self: *Elf) void { self.objects.deinit(gpa); self.shared_objects.deinit(gpa); - for (self.sections.items(.atom_list), self.sections.items(.free_list)) |*atoms, *free_list| { + for (self.sections.items(.atom_list_2), self.sections.items(.atom_list), self.sections.items(.free_list)) |*atom_list, *atoms, *free_list| { + atom_list.deinit(gpa); atoms.deinit(gpa); free_list.deinit(gpa); } @@ -3204,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void { } }; - for (slice.items(.shdr), slice.items(.atom_list)) |shdr, *atom_list| { + for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| { if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; + if (atom_list.atoms.items.len == 0) continue; var is_init_fini = false; var is_ctor_dtor = false; @@ -3219,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void { is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null; }, } - if (!is_init_fini and !is_ctor_dtor) continue; - if (atom_list.items.len == 0) continue; var entries = std.ArrayList(Entry).init(gpa); - try entries.ensureTotalCapacityPrecise(atom_list.items.len); + try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len); defer entries.deinit(); - for (atom_list.items) |ref| { + for (atom_list.atoms.items) |ref| { const atom_ptr = self.atom(ref).?; const object = atom_ptr.file(self).?.object; const priority = blk: { @@ -3246,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void { mem.sort(Entry, entries.items, self, Entry.lessThan); - atom_list.clearRetainingCapacity(); + atom_list.atoms.clearRetainingCapacity(); for (entries.items) |entry| { - atom_list.appendAssumeCapacity(entry.atom_ref); + atom_list.atoms.appendAssumeCapacity(entry.atom_ref); } } } @@ -3491,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { msec.output_section_index = backlinks[msec.output_section_index]; } - for (self.sections.items(.shdr)) |*shdr| { - if (shdr.sh_type != elf.SHT_RELA) continue; - // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections - // to point at symtab - // shdr.sh_link = backlinks[shdr.sh_link]; - shdr.sh_link = self.symtab_section_index.?; - shdr.sh_info = backlinks[shdr.sh_info]; + const slice = self.sections.slice(); + for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| { + atom_list.output_section_index = backlinks[atom_list.output_section_index]; + for (atom_list.atoms.items) |ref| { + self.atom(ref).?.output_section_index = atom_list.output_section_index; + } + if (shdr.sh_type == elf.SHT_RELA) { + // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections + // to point at symtab + // shdr.sh_link = backlinks[shdr.sh_link]; + shdr.sh_link = self.symtab_section_index.?; + shdr.sh_info = backlinks[shdr.sh_info]; + } } if (self.zigObjectPtr()) |zo| { @@ -3507,79 +3513,71 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { } } - for (self.objects.items) |index| { - const object = self.file(index).?.object; - for (object.section_chunks.items) |*chunk| { - chunk.output_section_index = backlinks[chunk.output_section_index]; - for (chunk.atoms.items) |atom_index| { - object.atom(atom_index).?.output_section_index = chunk.output_section_index; - } - } - } - for (self.comdat_group_sections.items) |*cg| { cg.shndx = backlinks[cg.shndx]; } if (self.symtab_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.strtab_section_index.?; } if (self.dynamic_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynstrtab_section_index.?; } if (self.dynsymtab_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynstrtab_section_index.?; } if (self.hash_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynsymtab_section_index.?; } if (self.gnu_hash_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynsymtab_section_index.?; } if (self.versym_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynsymtab_section_index.?; } if (self.verneed_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynstrtab_section_index.?; } if (self.rela_dyn_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynsymtab_section_index orelse 0; } if (self.rela_plt_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.dynsymtab_section_index.?; shdr.sh_info = self.plt_section_index.?; } if (self.eh_frame_rela_section_index) |index| { - const shdr = &self.sections.items(.shdr)[index]; + const shdr = &slice.items(.shdr)[index]; shdr.sh_link = self.symtab_section_index.?; shdr.sh_info = self.eh_frame_section_index.?; } } fn updateSectionSizes(self: *Elf) !void { - for (self.objects.items) |index| { - try self.file(index).?.object.allocateAtoms(self); + const slice = self.sections.slice(); + for (slice.items(.atom_list_2)) |*atom_list| { + if (atom_list.atoms.items.len == 0) continue; + atom_list.updateSize(self); + try atom_list.allocate(self); } - const slice = self.sections.slice(); if (self.requiresThunks()) { for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; @@ -4033,15 +4031,38 @@ fn allocateSpecialPhdrs(self: *Elf) void { } fn writeAtoms(self: *Elf) !void { - for (self.objects.items) |index| { - try self.file(index).?.object.writeAtoms(self); + const gpa = self.base.comp.gpa; + + var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa); + defer { + for (undefs.values()) |*refs| { + refs.deinit(); + } + undefs.deinit(); } - if (self.requiresThunks()) { - const gpa = self.base.comp.gpa; - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + const slice = self.sections.slice(); + var has_reloc_errors = false; + for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| { + if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (atom_list.atoms.items.len == 0) continue; + atom_list.write(&buffer, &undefs, self) catch |err| switch (err) { + error.UnsupportedCpuArch => { + try self.reportUnsupportedCpuArch(); + return error.FlushFailure; + }, + error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, + else => |e| return e, + }; + } + + try self.reportUndefinedSymbols(&undefs); + if (has_reloc_errors) return error.FlushFailure; + + if (self.requiresThunks()) { for (self.thunks.items) |th| { const thunk_size = th.size(self); try buffer.ensureUnusedCapacity(thunk_size); @@ -4993,7 +5014,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 { return off; } -pub fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { +fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { const gpa = self.base.comp.gpa; const max_notes = 4; @@ -5061,7 +5082,7 @@ fn reportMissingLibraryError( } } -pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { +fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { var err = try self.base.addErrorWithNotes(0); try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{ @tagName(self.getTarget().cpu.arch), @@ -5248,9 +5269,8 @@ fn fmtDumpState( try writer.print("object({d}) : {}", .{ index, object.fmtPath() }); if (!object.alive) try writer.writeAll(" : [*]"); try writer.writeByte('\n'); - try writer.print("{}{}{}{}{}{}\n", .{ + try writer.print("{}{}{}{}{}\n", .{ object.fmtAtoms(self), - object.fmtSectionChunks(self), object.fmtCies(self), object.fmtFdes(self), object.fmtSymtab(self), @@ -5274,6 +5294,14 @@ fn fmtDumpState( try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); } + const slice = self.sections.slice(); + { + try writer.writeAll("atom lists\n"); + for (slice.items(.shdr), slice.items(.atom_list_2), 0..) |shdr, atom_list, shndx| { + try writer.print("shdr({d}) : {s} : {}", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) }); + } + } + if (self.requiresThunks()) { try writer.writeAll("thunks\n"); for (self.thunks.items, 0..) |th, index| { @@ -5295,7 +5323,7 @@ fn fmtDumpState( } try writer.writeAll("\nOutput shdrs\n"); - for (self.sections.items(.shdr), self.sections.items(.phndx), 0..) |shdr, phndx, shndx| { + for (slice.items(.shdr), slice.items(.phndx), 0..) |shdr, phndx, shndx| { try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ shndx, phndx, @@ -5549,8 +5577,14 @@ const Section = struct { phndx: ?u32 = null, /// List of atoms contributing to this section. + /// TODO currently this is only used for relocations tracking in relocatable mode + /// but will be merged with atom_list_2. atom_list: std.ArrayListUnmanaged(Ref) = .{}, + /// List of atoms contributing to this section. + /// This can be used by sections that require special handling such as init/fini array, etc. + atom_list_2: AtomList = .{}, + /// Index of the last allocated atom in this section. last_atom: Ref = .{ .index = 0, .file = 0 }, @@ -5690,6 +5724,7 @@ const Air = @import("../Air.zig"); const Allocator = std.mem.Allocator; const Archive = @import("Elf/Archive.zig"); pub const Atom = @import("Elf/Atom.zig"); +const AtomList = @import("Elf/AtomList.zig"); const Cache = std.Build.Cache; const Path = Cache.Path; const Compilation = @import("../Compilation.zig"); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 0d063927ce..18c7a91c8f 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -17,7 +17,6 @@ relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, atoms: std.ArrayListUnmanaged(Atom) = .{}, atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{}, atoms_extra: std.ArrayListUnmanaged(u32) = .{}, -section_chunks: std.ArrayListUnmanaged(SectionChunk) = .{}, comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{}, comdat_group_data: std.ArrayListUnmanaged(u32) = .{}, @@ -59,10 +58,6 @@ pub fn deinit(self: *Object, allocator: Allocator) void { self.atoms.deinit(allocator); self.atoms_indexes.deinit(allocator); self.atoms_extra.deinit(allocator); - for (self.section_chunks.items) |*chunk| { - chunk.deinit(allocator); - } - self.section_chunks.deinit(allocator); self.comdat_groups.deinit(allocator); self.comdat_group_data.deinit(allocator); self.relocs.deinit(allocator); @@ -952,166 +947,9 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void { .flags = shdr.sh_flags, .type = shdr.sh_type, }); - const chunk = for (self.section_chunks.items) |*chunk| { - if (chunk.output_section_index == osec) break chunk; - } else blk: { - const chunk = try self.section_chunks.addOne(elf_file.base.comp.gpa); - chunk.* = .{ .output_section_index = osec }; - break :blk chunk; - }; - try chunk.atoms.append(elf_file.base.comp.gpa, atom_index); - } -} - -pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void { - for (self.section_chunks.items) |*chunk| { - chunk.updateSize(self); - } - - for (self.section_chunks.items) |*chunk| { - const alloc_res = try elf_file.allocateChunk(.{ - .shndx = chunk.output_section_index, - .size = chunk.size, - .alignment = chunk.alignment, - .requires_padding = false, - }); - chunk.value = @intCast(alloc_res.value); - - const slice = elf_file.sections.slice(); - const shdr = &slice.items(.shdr)[chunk.output_section_index]; - const last_atom_ref = &slice.items(.last_atom)[chunk.output_section_index]; - - const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom| - placement_atom.nextAtom(elf_file) == null - else - true; - if (expand_section) last_atom_ref.* = chunk.lastAtom(self).ref(); - shdr.sh_addralign = @max(shdr.sh_addralign, chunk.alignment.toByteUnits().?); - - { - var idx: usize = 0; - while (idx < chunk.atoms.items.len) : (idx += 1) { - const curr_atom_ptr = self.atom(chunk.atoms.items[idx]).?; - if (idx > 0) { - curr_atom_ptr.prev_atom_ref = .{ .index = chunk.atoms.items[idx - 1], .file = self.index }; - } - if (idx + 1 < chunk.atoms.items.len) { - curr_atom_ptr.next_atom_ref = .{ .index = chunk.atoms.items[idx + 1], .file = self.index }; - } - } - } - - if (elf_file.atom(alloc_res.placement)) |placement_atom| { - chunk.firstAtom(self).prev_atom_ref = placement_atom.ref(); - chunk.lastAtom(self).next_atom_ref = placement_atom.next_atom_ref; - placement_atom.next_atom_ref = chunk.firstAtom(self).ref(); - } - - // TODO if we had a link from Atom to parent Chunk we would not need to update Atom's value or osec index - for (chunk.atoms.items) |atom_index| { - const atom_ptr = self.atom(atom_index).?; - atom_ptr.output_section_index = chunk.output_section_index; - atom_ptr.value += chunk.value; - } - } -} - -pub fn writeAtoms(self: *Object, elf_file: *Elf) !void { - const gpa = elf_file.base.comp.gpa; - - var undefs = std.AutoArrayHashMap(Elf.SymbolResolver.Index, std.ArrayList(Elf.Ref)).init(gpa); - defer { - for (undefs.values()) |*refs| { - refs.deinit(); - } - undefs.deinit(); - } - - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); - - log.debug("writing atoms in {}", .{self.fmtPath()}); - - var has_reloc_errors = false; - for (self.section_chunks.items) |chunk| { - const osec = elf_file.sections.items(.shdr)[chunk.output_section_index]; - if (osec.sh_type == elf.SHT_NOBITS) continue; - - log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)}); - - try buffer.ensureUnusedCapacity(chunk.size); - buffer.appendNTimesAssumeCapacity(0, chunk.size); - - for (chunk.atoms.items) |atom_index| { - const atom_ptr = self.atom(atom_index).?; - assert(atom_ptr.alive); - - const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow; - const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; - - log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset }); - - const code = try self.codeDecompressAlloc(elf_file, atom_index); - defer gpa.free(code); - const out_code = buffer.items[offset..][0..size]; - @memcpy(out_code, code); - - const res = if (osec.sh_flags & elf.SHF_ALLOC == 0) - atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, &undefs) - else - atom_ptr.resolveRelocsAlloc(elf_file, out_code); - _ = res catch |err| switch (err) { - error.UnsupportedCpuArch => { - try elf_file.reportUnsupportedCpuArch(); - return error.FlushFailure; - }, - error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, - else => |e| return e, - }; - } - - try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file)); - buffer.clearRetainingCapacity(); - } - - try elf_file.reportUndefinedSymbols(&undefs); - if (has_reloc_errors) return error.FlushFailure; -} - -pub fn writeAtomsRelocatable(self: *Object, elf_file: *Elf) !void { - const gpa = elf_file.base.comp.gpa; - - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); - - log.debug("writing atoms in {}", .{self.fmtPath()}); - - for (self.section_chunks.items) |chunk| { - const osec = elf_file.sections.items(.shdr)[chunk.output_section_index]; - if (osec.sh_type == elf.SHT_NOBITS) continue; - - log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)}); - - try buffer.ensureUnusedCapacity(chunk.size); - buffer.appendNTimesAssumeCapacity(0, chunk.size); - - for (chunk.atoms.items) |atom_index| { - const atom_ptr = self.atom(atom_index).?; - assert(atom_ptr.alive); - - const offset = math.cast(usize, atom_ptr.value - chunk.value) orelse return error.Overflow; - const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; - - log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset }); - - const code = try self.codeDecompressAlloc(elf_file, atom_index); - defer gpa.free(code); - const out_code = buffer.items[offset..][0..size]; - @memcpy(out_code, code); - } - - try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file)); - buffer.clearRetainingCapacity(); + const atom_list = &elf_file.sections.items(.atom_list_2)[osec]; + atom_list.output_section_index = osec; + try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref()); } } @@ -1585,29 +1423,6 @@ fn formatAtoms( } } -pub fn fmtSectionChunks(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatSectionChunks) { - return .{ .data = .{ - .object = self, - .elf_file = elf_file, - } }; -} - -fn formatSectionChunks( - ctx: FormatContext, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = unused_fmt_string; - _ = options; - const object = ctx.object; - const elf_file = ctx.elf_file; - try writer.writeAll(" section chunks\n"); - for (object.section_chunks.items) |chunk| { - try writer.print(" {}\n", .{chunk.fmt(elf_file)}); - } -} - pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) { return .{ .data = .{ .object = self, @@ -1709,90 +1524,6 @@ const InArchive = struct { size: u32, }; -const SectionChunk = struct { - value: i64 = 0, - size: u64 = 0, - alignment: Atom.Alignment = .@"1", - output_section_index: u32 = 0, - atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, - - fn deinit(chunk: *SectionChunk, allocator: Allocator) void { - chunk.atoms.deinit(allocator); - } - - fn address(chunk: SectionChunk, elf_file: *Elf) i64 { - const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index]; - return @as(i64, @intCast(shdr.sh_addr)) + chunk.value; - } - - fn offset(chunk: SectionChunk, elf_file: *Elf) u64 { - const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index]; - return shdr.sh_offset + @as(u64, @intCast(chunk.value)); - } - - fn updateSize(chunk: *SectionChunk, object: *Object) void { - for (chunk.atoms.items) |atom_index| { - const atom_ptr = object.atom(atom_index).?; - assert(atom_ptr.alive); - const off = atom_ptr.alignment.forward(chunk.size); - const padding = off - chunk.size; - atom_ptr.value = @intCast(off); - chunk.size += padding + atom_ptr.size; - chunk.alignment = chunk.alignment.max(atom_ptr.alignment); - } - } - - fn firstAtom(chunk: SectionChunk, object: *Object) *Atom { - assert(chunk.atoms.items.len > 0); - return object.atom(chunk.atoms.items[0]).?; - } - - fn lastAtom(chunk: SectionChunk, object: *Object) *Atom { - assert(chunk.atoms.items.len > 0); - return object.atom(chunk.atoms.items[chunk.atoms.items.len - 1]).?; - } - - pub fn format( - chunk: SectionChunk, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = chunk; - _ = unused_fmt_string; - _ = options; - _ = writer; - @compileError("do not format SectionChunk directly"); - } - - const FormatCtx = struct { SectionChunk, *Elf }; - - pub fn fmt(chunk: SectionChunk, elf_file: *Elf) std.fmt.Formatter(format2) { - return .{ .data = .{ chunk, elf_file } }; - } - - fn format2( - ctx: FormatCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = unused_fmt_string; - _ = options; - const chunk, const elf_file = ctx; - try writer.print("chunk : @{x} : shdr({d}) : align({x}) : size({x})", .{ - chunk.address(elf_file), chunk.output_section_index, - chunk.alignment.toByteUnits() orelse 0, chunk.size, - }); - try writer.writeAll(" : atoms{ "); - for (chunk.atoms.items, 0..) |atom_index, i| { - try writer.print("{d}", .{atom_index}); - if (i < chunk.atoms.items.len - 1) try writer.writeAll(", "); - } - try writer.writeAll(" }"); - } -}; - const Object = @This(); const std = @import("std"); @@ -1807,6 +1538,7 @@ const mem = std.mem; const Allocator = mem.Allocator; const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); +const AtomList = @import("AtomList.zig"); const Cie = eh_frame.Cie; const Elf = @import("../Elf.zig"); const Fde = eh_frame.Fde; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 5df6bb9946..5fc0d5790b 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -353,11 +353,13 @@ fn initComdatGroups(elf_file: *Elf) !void { } fn updateSectionSizes(elf_file: *Elf) !void { - for (elf_file.objects.items) |index| { - try elf_file.file(index).?.object.allocateAtoms(elf_file); + const slice = elf_file.sections.slice(); + for (slice.items(.atom_list_2)) |*atom_list| { + if (atom_list.atoms.items.len == 0) continue; + atom_list.updateSize(elf_file); + try atom_list.allocate(elf_file); } - const slice = elf_file.sections.slice(); for (slice.items(.shdr), 0..) |*shdr, shndx| { const atom_list = slice.items(.atom_list)[shndx]; if (shdr.sh_type != elf.SHT_RELA) continue; @@ -444,8 +446,16 @@ fn allocateAllocSections(elf_file: *Elf) !void { } fn writeAtoms(elf_file: *Elf) !void { - for (elf_file.objects.items) |index| { - try elf_file.file(index).?.object.writeAtomsRelocatable(elf_file); + const gpa = elf_file.base.comp.gpa; + + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + + const slice = elf_file.sections.slice(); + for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| { + if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (atom_list.atoms.items.len == 0) continue; + try atom_list.writeRelocatable(&buffer, elf_file); } } From f3d527c0822bd24bcd01fbcf3d670a7633a92468 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 12:11:04 +0200 Subject: [PATCH 32/35] elf: migrate thunks to the new mechanism (AtomList) --- src/link/Elf.zig | 61 +++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 67969b7fb7..333501b29f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3572,19 +3572,26 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { fn updateSectionSizes(self: *Elf) !void { const slice = self.sections.slice(); - for (slice.items(.atom_list_2)) |*atom_list| { + for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| { if (atom_list.atoms.items.len == 0) continue; + if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; atom_list.updateSize(self); try atom_list.allocate(self); } if (self.requiresThunks()) { - for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { + for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| { if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; - if (atom_list.items.len == 0) continue; + if (atom_list.atoms.items.len == 0) continue; // Create jump/branch range extenders if needed. - try self.createThunks(shdr, @intCast(shndx)); + try self.createThunks(atom_list); + try atom_list.allocate(self); + } + + // FIXME:JK this will hopefully not be needed once we create a link from Atom/Thunk to AtomList. + for (self.thunks.items) |*th| { + th.value += slice.items(.atom_list_2)[th.output_section_index].value; } } @@ -4066,7 +4073,7 @@ fn writeAtoms(self: *Elf) !void { for (self.thunks.items) |th| { const thunk_size = th.size(self); try buffer.ensureUnusedCapacity(thunk_size); - const shdr = self.sections.items(.shdr)[th.output_section_index]; + const shdr = slice.items(.shdr)[th.output_section_index]; const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset; try th.write(self, buffer.writer()); assert(buffer.items.len == thunk_size); @@ -5613,9 +5620,10 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { }; } -fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { +fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { const gpa = elf_file.base.comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; + // A branch will need an extender if its target is larger than // `2^(jump_bits - 1) - margin` where margin is some arbitrary number. const max_distance = switch (cpu_arch) { @@ -5623,36 +5631,44 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { .x86_64, .riscv64 => unreachable, else => @panic("unhandled arch"), }; - const atoms = elf_file.sections.items(.atom_list)[shndx].items; - assert(atoms.len > 0); - for (atoms) |ref| { + const advance = struct { + fn advance(list: *AtomList, size: u64, alignment: Atom.Alignment) !i64 { + const offset = alignment.forward(list.size); + const padding = offset - list.size; + list.size += padding + size; + list.alignment = list.alignment.max(alignment); + return @intCast(offset); + } + }.advance; + + for (atom_list.atoms.items) |ref| { elf_file.atom(ref).?.value = -1; } var i: usize = 0; - while (i < atoms.len) { + while (i < atom_list.atoms.items.len) { const start = i; - const start_atom = elf_file.atom(atoms[start]).?; + const start_atom = elf_file.atom(atom_list.atoms.items[start]).?; assert(start_atom.alive); - start_atom.value = try advanceSection(shdr, start_atom.size, start_atom.alignment); + start_atom.value = try advance(atom_list, start_atom.size, start_atom.alignment); i += 1; - while (i < atoms.len) : (i += 1) { - const atom_ptr = elf_file.atom(atoms[i]).?; + while (i < atom_list.atoms.items.len) : (i += 1) { + const atom_ptr = elf_file.atom(atom_list.atoms.items[i]).?; assert(atom_ptr.alive); - if (@as(i64, @intCast(atom_ptr.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance) + if (@as(i64, @intCast(atom_ptr.alignment.forward(atom_list.size))) - start_atom.value >= max_distance) break; - atom_ptr.value = try advanceSection(shdr, atom_ptr.size, atom_ptr.alignment); + atom_ptr.value = try advance(atom_list, atom_ptr.size, atom_ptr.alignment); } // Insert a thunk at the group end const thunk_index = try elf_file.addThunk(); const thunk_ptr = elf_file.thunk(thunk_index); - thunk_ptr.output_section_index = shndx; + thunk_ptr.output_section_index = atom_list.output_section_index; // Scan relocs in the group and create trampolines for any unreachable callsite - for (atoms[start..i]) |ref| { + for (atom_list.atoms.items[start..i]) |ref| { const atom_ptr = elf_file.atom(ref).?; const file_ptr = atom_ptr.file(elf_file).?; log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) }); @@ -5682,18 +5698,11 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file); } - thunk_ptr.value = try advanceSection(shdr, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); + thunk_ptr.value = try advance(atom_list, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) }); } } -fn advanceSection(shdr: *elf.Elf64_Shdr, adv_size: u64, alignment: Atom.Alignment) !i64 { - const offset = alignment.forward(shdr.sh_size); - const padding = offset - shdr.sh_size; - shdr.sh_size += padding + adv_size; - shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); - return @intCast(offset); -} const std = @import("std"); const build_options = @import("build_options"); From b6caab63cb85d195230f939c4fc408b680866e22 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 13:44:06 +0200 Subject: [PATCH 33/35] elf: actually commit AtomList.zig --- src/link/Elf/AtomList.zig | 206 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 src/link/Elf/AtomList.zig diff --git a/src/link/Elf/AtomList.zig b/src/link/Elf/AtomList.zig new file mode 100644 index 0000000000..890f1872b5 --- /dev/null +++ b/src/link/Elf/AtomList.zig @@ -0,0 +1,206 @@ +value: i64 = 0, +size: u64 = 0, +alignment: Atom.Alignment = .@"1", +output_section_index: u32 = 0, +atoms: std.ArrayListUnmanaged(Elf.Ref) = .{}, + +pub fn deinit(list: *AtomList, allocator: Allocator) void { + list.atoms.deinit(allocator); +} + +pub fn address(list: AtomList, elf_file: *Elf) i64 { + const shdr = elf_file.sections.items(.shdr)[list.output_section_index]; + return @as(i64, @intCast(shdr.sh_addr)) + list.value; +} + +pub fn offset(list: AtomList, elf_file: *Elf) u64 { + const shdr = elf_file.sections.items(.shdr)[list.output_section_index]; + return shdr.sh_offset + @as(u64, @intCast(list.value)); +} + +pub fn updateSize(list: *AtomList, elf_file: *Elf) void { + for (list.atoms.items) |ref| { + const atom_ptr = elf_file.atom(ref).?; + assert(atom_ptr.alive); + const off = atom_ptr.alignment.forward(list.size); + const padding = off - list.size; + atom_ptr.value = @intCast(off); + list.size += padding + atom_ptr.size; + list.alignment = list.alignment.max(atom_ptr.alignment); + } +} + +pub fn allocate(list: *AtomList, elf_file: *Elf) !void { + const alloc_res = try elf_file.allocateChunk(.{ + .shndx = list.output_section_index, + .size = list.size, + .alignment = list.alignment, + .requires_padding = false, + }); + list.value = @intCast(alloc_res.value); + + const slice = elf_file.sections.slice(); + const shdr = &slice.items(.shdr)[list.output_section_index]; + const last_atom_ref = &slice.items(.last_atom)[list.output_section_index]; + + const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom| + placement_atom.nextAtom(elf_file) == null + else + true; + if (expand_section) last_atom_ref.* = list.lastAtom(elf_file).ref(); + shdr.sh_addralign = @max(shdr.sh_addralign, list.alignment.toByteUnits().?); + + // FIXME:JK this currently ignores Thunks as valid chunks. + { + var idx: usize = 0; + while (idx < list.atoms.items.len) : (idx += 1) { + const curr_atom_ptr = elf_file.atom(list.atoms.items[idx]).?; + if (idx > 0) { + curr_atom_ptr.prev_atom_ref = list.atoms.items[idx - 1]; + } + if (idx + 1 < list.atoms.items.len) { + curr_atom_ptr.next_atom_ref = list.atoms.items[idx + 1]; + } + } + } + + if (elf_file.atom(alloc_res.placement)) |placement_atom| { + list.firstAtom(elf_file).prev_atom_ref = placement_atom.ref(); + list.lastAtom(elf_file).next_atom_ref = placement_atom.next_atom_ref; + placement_atom.next_atom_ref = list.firstAtom(elf_file).ref(); + } + + // FIXME:JK if we had a link from Atom to parent AtomList we would not need to update Atom's value or osec index + for (list.atoms.items) |ref| { + const atom_ptr = elf_file.atom(ref).?; + atom_ptr.output_section_index = list.output_section_index; + atom_ptr.value += list.value; + } +} + +pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + const osec = elf_file.sections.items(.shdr)[list.output_section_index]; + assert(osec.sh_type != elf.SHT_NOBITS); + + log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); + + try buffer.ensureUnusedCapacity(list.size); + buffer.appendNTimesAssumeCapacity(0, list.size); + + for (list.atoms.items) |ref| { + const atom_ptr = elf_file.atom(ref).?; + assert(atom_ptr.alive); + + const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow; + const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; + + log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); + + const object = atom_ptr.file(elf_file).?.object; + const code = try object.codeDecompressAlloc(elf_file, ref.index); + defer gpa.free(code); + const out_code = buffer.items[off..][0..size]; + @memcpy(out_code, code); + + if (osec.sh_flags & elf.SHF_ALLOC == 0) + try atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, undefs) + else + try atom_ptr.resolveRelocsAlloc(elf_file, out_code); + } + + try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file)); + buffer.clearRetainingCapacity(); +} + +pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + const osec = elf_file.sections.items(.shdr)[list.output_section_index]; + assert(osec.sh_type != elf.SHT_NOBITS); + + log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); + + try buffer.ensureUnusedCapacity(list.size); + buffer.appendNTimesAssumeCapacity(0, list.size); + + for (list.atoms.items) |ref| { + const atom_ptr = elf_file.atom(ref).?; + assert(atom_ptr.alive); + + const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow; + const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; + + log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); + + const object = atom_ptr.file(elf_file).?.object; + const code = try object.codeDecompressAlloc(elf_file, ref.index); + defer gpa.free(code); + const out_code = buffer.items[off..][0..size]; + @memcpy(out_code, code); + } + + try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file)); + buffer.clearRetainingCapacity(); +} + +pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom { + assert(list.atoms.items.len > 0); + return elf_file.atom(list.atoms.items[0]).?; +} + +pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom { + assert(list.atoms.items.len > 0); + return elf_file.atom(list.atoms.items[list.atoms.items.len - 1]).?; +} + +pub fn format( + list: AtomList, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = list; + _ = unused_fmt_string; + _ = options; + _ = writer; + @compileError("do not format AtomList directly"); +} + +const FormatCtx = struct { AtomList, *Elf }; + +pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) { + return .{ .data = .{ list, elf_file } }; +} + +fn format2( + ctx: FormatCtx, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) !void { + _ = unused_fmt_string; + _ = options; + const list, const elf_file = ctx; + try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{ + list.address(elf_file), list.output_section_index, + list.alignment.toByteUnits() orelse 0, list.size, + }); + try writer.writeAll(" : atoms{ "); + for (list.atoms.items, 0..) |ref, i| { + try writer.print("{}", .{ref}); + if (i < list.atoms.items.len - 1) try writer.writeAll(", "); + } + try writer.writeAll(" }"); +} + +const assert = std.debug.assert; +const elf = std.elf; +const log = std.log.scoped(.link); +const math = std.math; +const std = @import("std"); + +const Allocator = std.mem.Allocator; +const Atom = @import("Atom.zig"); +const AtomList = @This(); +const Elf = @import("../Elf.zig"); +const Object = @import("Object.zig"); From 516955dbdb6cb1a54a00e94dff516d5bfbe6dfc4 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 13:45:16 +0200 Subject: [PATCH 34/35] elf: add AtomList.zig to CMakeLists.txt --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8348b45cfd..781076ef61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -600,6 +600,7 @@ set(ZIG_STAGE2_SOURCES src/link/Elf.zig src/link/Elf/Archive.zig src/link/Elf/Atom.zig + src/link/Elf/AtomList.zig src/link/Elf/LdScript.zig src/link/Elf/LinkerDefined.zig src/link/Elf/Object.zig From e1d5bb365b3b8d645fbdfc4ffb6a14ef3bb0e766 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 4 Sep 2024 15:55:38 +0200 Subject: [PATCH 35/35] elf: fix 32bit build --- src/link/Elf/AtomList.zig | 10 ++++++---- src/link/Elf/eh_frame.zig | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/link/Elf/AtomList.zig b/src/link/Elf/AtomList.zig index 890f1872b5..51407ca6d9 100644 --- a/src/link/Elf/AtomList.zig +++ b/src/link/Elf/AtomList.zig @@ -85,8 +85,9 @@ pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_fi log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); - try buffer.ensureUnusedCapacity(list.size); - buffer.appendNTimesAssumeCapacity(0, list.size); + const list_size = math.cast(usize, list.size) orelse return error.Overflow; + try buffer.ensureUnusedCapacity(list_size); + buffer.appendNTimesAssumeCapacity(0, list_size); for (list.atoms.items) |ref| { const atom_ptr = elf_file.atom(ref).?; @@ -120,8 +121,9 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); - try buffer.ensureUnusedCapacity(list.size); - buffer.appendNTimesAssumeCapacity(0, list.size); + const list_size = math.cast(usize, list.size) orelse return error.Overflow; + try buffer.ensureUnusedCapacity(list_size); + buffer.appendNTimesAssumeCapacity(0, list_size); for (list.atoms.items) |ref| { const atom_ptr = elf_file.atom(ref).?; diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index a9e3e618cb..b520c94aaf 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -235,7 +235,7 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { var offset: usize = if (elf_file.zigObjectPtr()) |zo| blk: { const sym = zo.symbol(zo.eh_frame_index orelse break :blk 0); - break :blk sym.atom(elf_file).?.size; + break :blk math.cast(usize, sym.atom(elf_file).?.size) orelse return error.Overflow; } else 0; var cies = std.ArrayList(Cie).init(gpa);