From 5cb51c10debd3e9542e35e22648bca2a8b59259e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 2 Sep 2024 11:42:47 +0200 Subject: elf: fix relocatable mode --- src/link/Elf.zig | 32 ++++--------- 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, 67 insertions(+), 117 deletions(-) (limited to 'src') 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; - - // // Create jump/branch range extenders if needed. - // try self.createThunks(shdr, @intCast(shndx)); - // } - // } + 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)); + } + } 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, -- cgit v1.2.3