authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-02 08:42:47+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 13:34:26+02:00
logf87a7251a3f9ae7259c64f458823117370071943
treeecbc004d6a17f7d20da489cc2d908a78ccc61ad5
parent874ef6308e6e438985a141310b94028de33286dc

elf: actually write allocated atoms in object files


2 files changed, 77 insertions(+), 102 deletions(-)

src/link/Elf.zig+5-97
...@@ -4037,107 +4037,19 @@ fn allocateSpecialPhdrs(self: *Elf) void {...@@ -4037,107 +4037,19 @@ fn allocateSpecialPhdrs(self: *Elf) void {
4037}4037}
40384038
4039fn writeAtoms(self: *Elf) !void {4039fn writeAtoms(self: *Elf) !void {
4040 const gpa = self.base.comp.gpa;4040 for (self.objects.items) |index| {
40414041 try self.file(index).?.object.writeAtoms(self);
4042 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
4043 defer {
4044 for (undefs.values()) |*refs| {
4045 refs.deinit();
4046 }
4047 undefs.deinit();
4048 }
4049
4050 var has_reloc_errors = false;
4051 const slice = self.sections.slice();
4052 for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| {
4053 if (shdr.sh_type == elf.SHT_NULL) continue;
4054 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4055 if (atom_list.items.len == 0) continue;
4056
4057 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
4058
4059 // TODO really, really handle debug section separately
4060 const base_offset = if (self.zigObjectPtr()) |zo| base_offset: {
4061 for ([_]?Symbol.Index{
4062 zo.text_index,
4063 zo.rodata_index,
4064 zo.data_relro_index,
4065 zo.data_index,
4066 zo.tdata_index,
4067 zo.eh_frame_index,
4068 zo.debug_info_index,
4069 zo.debug_abbrev_index,
4070 zo.debug_aranges_index,
4071 zo.debug_str_index,
4072 zo.debug_line_index,
4073 zo.debug_line_str_index,
4074 zo.debug_loclists_index,
4075 zo.debug_rnglists_index,
4076 }) |maybe_sym_index| {
4077 const sym_index = maybe_sym_index orelse continue;
4078 const sym = zo.symbol(sym_index);
4079 const atom_ptr = sym.atom(self).?;
4080 if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size;
4081 }
4082 break :base_offset 0;
4083 } else 0;
4084 const sh_offset = shdr.sh_offset + base_offset;
4085 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
4086
4087 const buffer = try gpa.alloc(u8, sh_size);
4088 defer gpa.free(buffer);
4089 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
4090 shdr.sh_flags & elf.SHF_EXECINSTR != 0 and self.getTarget().cpu.arch == .x86_64)
4091 0xcc // int3
4092 else
4093 0;
4094 @memset(buffer, padding_byte);
4095
4096 for (atom_list.items) |ref| {
4097 const atom_ptr = self.atom(ref).?;
4098 assert(atom_ptr.alive);
4099
4100 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse
4101 return error.Overflow;
4102 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
4103
4104 log.debug("writing atom({}) at 0x{x}", .{ ref, sh_offset + offset });
4105
4106 // TODO decompress directly into provided buffer
4107 const out_code = buffer[offset..][0..size];
4108 const in_code = switch (atom_ptr.file(self).?) {
4109 .object => |x| try x.codeDecompressAlloc(self, ref.index),
4110 .zig_object => |x| try x.codeAlloc(self, ref.index),
4111 else => unreachable,
4112 };
4113 defer gpa.free(in_code);
4114 @memcpy(out_code, in_code);
4115
4116 const res = if (shdr.sh_flags & elf.SHF_ALLOC == 0)
4117 atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs)
4118 else
4119 atom_ptr.resolveRelocsAlloc(self, out_code);
4120 _ = res catch |err| switch (err) {
4121 error.UnsupportedCpuArch => {
4122 try self.reportUnsupportedCpuArch();
4123 return error.FlushFailure;
4124 },
4125 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
4126 else => |e| return e,
4127 };
4128 }
4129
4130 try self.base.file.?.pwriteAll(buffer, sh_offset);
4131 }4042 }
41324043
4133 if (self.requiresThunks()) {4044 if (self.requiresThunks()) {
4045 const gpa = self.base.comp.gpa;
4134 var buffer = std.ArrayList(u8).init(gpa);4046 var buffer = std.ArrayList(u8).init(gpa);
4135 defer buffer.deinit();4047 defer buffer.deinit();
41364048
4137 for (self.thunks.items) |th| {4049 for (self.thunks.items) |th| {
4138 const thunk_size = th.size(self);4050 const thunk_size = th.size(self);
4139 try buffer.ensureUnusedCapacity(thunk_size);4051 try buffer.ensureUnusedCapacity(thunk_size);
4140 const shdr = slice.items(.shdr)[th.output_section_index];4052 const shdr = self.sections.items(.shdr)[th.output_section_index];
4141 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;4053 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;
4142 try th.write(self, buffer.writer());4054 try th.write(self, buffer.writer());
4143 assert(buffer.items.len == thunk_size);4055 assert(buffer.items.len == thunk_size);
...@@ -4145,10 +4057,6 @@ fn writeAtoms(self: *Elf) !void {...@@ -4145,10 +4057,6 @@ fn writeAtoms(self: *Elf) !void {
4145 buffer.clearRetainingCapacity();4057 buffer.clearRetainingCapacity();
4146 }4058 }
4147 }4059 }
4148
4149 try self.reportUndefinedSymbols(&undefs);
4150
4151 if (has_reloc_errors) return error.FlushFailure;
4152}4060}
41534061
4154pub fn updateSymtabSize(self: *Elf) !void {4062pub fn updateSymtabSize(self: *Elf) !void {
...@@ -5089,7 +4997,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {...@@ -5089,7 +4997,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
5089 return off;4997 return off;
5090}4998}
50914999
5092fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {5000pub fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
5093 const gpa = self.base.comp.gpa;5001 const gpa = self.base.comp.gpa;
5094 const max_notes = 4;5002 const max_notes = 4;
50955003
src/link/Elf/Object.zig+72-5
...@@ -978,6 +978,68 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void {...@@ -978,6 +978,68 @@ pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void {
978 }978 }
979}979}
980980
981pub fn writeAtoms(self: *Object, elf_file: *Elf) !void {
982 const gpa = elf_file.base.comp.gpa;
983
984 var undefs = std.AutoArrayHashMap(Elf.SymbolResolver.Index, std.ArrayList(Elf.Ref)).init(gpa);
985 defer {
986 for (undefs.values()) |*refs| {
987 refs.deinit();
988 }
989 undefs.deinit();
990 }
991
992 var buffer = std.ArrayList(u8).init(gpa);
993 defer buffer.deinit();
994
995 log.debug("writing atoms in {}", .{self.fmtPath()});
996
997 var has_reloc_errors = false;
998 for (self.section_chunks.items) |chunk| {
999 const osec = elf_file.sections.items(.shdr)[chunk.output_section_index];
1000 if (osec.sh_type == elf.SHT_NOBITS) continue;
1001
1002 log.debug(" in section '{s}'", .{elf_file.getShString(osec.sh_name)});
1003
1004 try buffer.ensureUnusedCapacity(chunk.size);
1005 buffer.appendNTimesAssumeCapacity(0, chunk.size);
1006
1007 for (chunk.atoms.items) |atom_index| {
1008 const atom_ptr = self.atom(atom_index).?;
1009 assert(atom_ptr.alive);
1010
1011 const offset = math.cast(usize, atom_ptr.value) orelse return error.Overflow;
1012 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
1013
1014 log.debug(" * atom({d}) at 0x{x}", .{ atom_index, chunk.offset(elf_file) + offset });
1015
1016 const code = try self.codeDecompressAlloc(elf_file, atom_index);
1017 defer gpa.free(code);
1018 const out_code = buffer.items[offset..][0..size];
1019 @memcpy(out_code, code);
1020
1021 const res = if (osec.sh_flags & elf.SHF_ALLOC == 0)
1022 atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, &undefs)
1023 else
1024 atom_ptr.resolveRelocsAlloc(elf_file, out_code);
1025 _ = res catch |err| switch (err) {
1026 error.UnsupportedCpuArch => {
1027 try elf_file.reportUnsupportedCpuArch();
1028 return error.FlushFailure;
1029 },
1030 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
1031 else => |e| return e,
1032 };
1033 }
1034
1035 try elf_file.base.file.?.pwriteAll(buffer.items, chunk.offset(elf_file));
1036 buffer.clearRetainingCapacity();
1037 }
1038
1039 try elf_file.reportUndefinedSymbols(&undefs);
1040 if (has_reloc_errors) return error.FlushFailure;
1041}
1042
981pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {1043pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
982 for (self.atoms_indexes.items) |atom_index| {1044 for (self.atoms_indexes.items) |atom_index| {
983 const atom_ptr = self.atom(atom_index) orelse continue;1045 const atom_ptr = self.atom(atom_index) orelse continue;
...@@ -1544,12 +1606,12 @@ fn formatComdatGroups(...@@ -1544,12 +1606,12 @@ fn formatComdatGroups(
1544 }1606 }
1545}1607}
15461608
1547pub fn fmtPath(self: *Object) std.fmt.Formatter(formatPath) {1609pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) {
1548 return .{ .data = self };1610 return .{ .data = self };
1549}1611}
15501612
1551fn formatPath(1613fn formatPath(
1552 object: *Object,1614 object: Object,
1553 comptime unused_fmt_string: []const u8,1615 comptime unused_fmt_string: []const u8,
1554 options: std.fmt.FormatOptions,1616 options: std.fmt.FormatOptions,
1555 writer: anytype,1617 writer: anytype,
...@@ -1586,13 +1648,18 @@ const SectionChunk = struct {...@@ -1586,13 +1648,18 @@ const SectionChunk = struct {
1586 return @as(i64, @intCast(shdr.sh_addr)) + chunk.value;1648 return @as(i64, @intCast(shdr.sh_addr)) + chunk.value;
1587 }1649 }
15881650
1651 fn offset(chunk: SectionChunk, elf_file: *Elf) u64 {
1652 const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index];
1653 return shdr.sh_offset + @as(u64, @intCast(chunk.value));
1654 }
1655
1589 fn updateSize(chunk: *SectionChunk, object: *Object) void {1656 fn updateSize(chunk: *SectionChunk, object: *Object) void {
1590 for (chunk.atoms.items) |atom_index| {1657 for (chunk.atoms.items) |atom_index| {
1591 const atom_ptr = object.atom(atom_index).?;1658 const atom_ptr = object.atom(atom_index).?;
1592 assert(atom_ptr.alive);1659 assert(atom_ptr.alive);
1593 const offset = atom_ptr.alignment.forward(chunk.size);1660 const off = atom_ptr.alignment.forward(chunk.size);
1594 const padding = offset - chunk.size;1661 const padding = off - chunk.size;
1595 atom_ptr.value = @intCast(offset);1662 atom_ptr.value = @intCast(off);
1596 chunk.size += padding + atom_ptr.size;1663 chunk.size += padding + atom_ptr.size;
1597 chunk.alignment = chunk.alignment.max(atom_ptr.alignment);1664 chunk.alignment = chunk.alignment.max(atom_ptr.alignment);
1598 }1665 }