Commit 53340544c6
Changed files (2)
src
link
src/link/Elf/Object.zig
@@ -20,6 +20,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
alive: bool = true,
num_dynrelocs: u32 = 0,
+output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},
output_symtab_size: Elf.SymtabSize = .{},
pub fn isObject(file: std.fs.File) bool {
@@ -42,6 +43,10 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
self.comdat_groups.deinit(allocator);
self.fdes.deinit(allocator);
self.cies.deinit(allocator);
+ for (self.output_sections.values()) |*list| {
+ list.deinit(allocator);
+ }
+ self.output_sections.deinit(allocator);
}
pub fn parse(self: *Object, elf_file: *Elf) !void {
@@ -193,7 +198,7 @@ fn addAtom(
}
}
-pub fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
+fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
const name = blk: {
const name = self.strings.getAssumeExists(shdr.sh_name);
if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
@@ -601,6 +606,30 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
}
}
+pub fn initOutputSections(self: Object, elf_file: *Elf) !void {
+ for (self.atoms.items) |atom_index| {
+ const atom = elf_file.atom(atom_index) orelse continue;
+ if (!atom.flags.alive) continue;
+ const shdr = atom.inputShdr(elf_file);
+ _ = try self.initOutputSection(elf_file, shdr);
+ }
+}
+
+pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
+ for (self.atoms.items) |atom_index| {
+ const atom = elf_file.atom(atom_index) orelse continue;
+ if (!atom.flags.alive) continue;
+ const shdr = atom.inputShdr(elf_file);
+ atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
+
+ if (shdr.sh_type == elf.SHT_NOBITS) continue;
+ const gpa = elf_file.base.allocator;
+ const gop = try self.output_sections.getOrPut(gpa, atom.output_section_index);
+ if (!gop.found_existing) gop.value_ptr.* = .{};
+ try gop.value_ptr.append(gpa, atom_index);
+ }
+}
+
pub fn updateSectionSizes(self: Object, elf_file: *Elf) void {
for (self.atoms.items) |atom_index| {
const atom = elf_file.atom(atom_index) orelse continue;
@@ -640,6 +669,24 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
}
}
+pub fn writeAtoms(self: Object, elf_file: *Elf, output_section_index: u16, buffer: []u8) !void {
+ const gpa = elf_file.base.allocator;
+ const atom_list = self.output_sections.get(output_section_index) orelse return;
+ const shdr = elf_file.shdrs.items[output_section_index];
+ for (atom_list.items) |atom_index| {
+ const atom = elf_file.atom(atom_index).?;
+ assert(atom.flags.alive);
+ const offset = atom.value - shdr.sh_addr;
+ log.debug("writing atom({d}) at 0x{x}", .{ atom_index, shdr.sh_offset + offset });
+ // TODO decompress directly into provided buffer
+ const out_code = buffer[offset..][0..atom.size];
+ const in_code = try self.codeDecompressAlloc(elf_file, atom_index);
+ defer gpa.free(in_code);
+ @memcpy(out_code, in_code);
+ try atom.resolveRelocs(elf_file, out_code);
+ }
+}
+
pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
src/link/Elf.zig
@@ -1245,6 +1245,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
// Generate and emit non-incremental sections.
try self.initSections();
try self.sortSections();
+ for (self.objects.items) |index| {
+ try self.file(index).?.object.addAtomsToOutputSections(self);
+ }
try self.updateSectionSizes();
try self.allocateSections();
@@ -1424,7 +1427,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
phdr_table_load.p_filesz = 0;
self.phdr_table_dirty = false;
- }
+ } else try self.writePhdrs();
if (self.shdr_table_dirty) {
const shsize: u64 = switch (self.ptr_width) {
@@ -1476,8 +1479,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
self.shdr_table_dirty = false;
}
+ try self.writeAtoms();
try self.writeSyntheticSections();
- try self.writeObjects();
if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {
log.debug("flushing. no_entry_point_found = true", .{});
@@ -1485,7 +1488,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
} else {
log.debug("flushing. no_entry_point_found = false", .{});
self.error_flags.no_entry_point_found = false;
- try self.writeElfHeader();
+ try self.writeHeader();
}
// Dump the state for easy debugging.
@@ -1756,30 +1759,6 @@ fn scanRelocs(self: *Elf) !void {
}
}
-fn writeObjects(self: *Elf) !void {
- const gpa = self.base.allocator;
-
- for (self.objects.items) |index| {
- const object = self.file(index).?.object;
- for (object.atoms.items) |atom_index| {
- const atom_ptr = self.atom(atom_index) orelse continue;
- if (!atom_ptr.flags.alive) continue;
-
- const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
- if (shdr.sh_type == elf.SHT_NOBITS) continue;
- if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections
-
- const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
- log.debug("writing atom({d}) at 0x{x}", .{ atom_ptr.atom_index, file_offset });
- const code = try object.codeDecompressAlloc(self, atom_ptr.atom_index);
- defer gpa.free(code);
-
- try atom_ptr.resolveRelocs(self, code);
- try self.base.file.?.pwriteAll(code, file_offset);
- }
- }
-}
-
fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -2480,7 +2459,14 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64)
}
}
-fn writeElfHeader(self: *Elf) !void {
+fn writePhdrs(self: *Elf) !void {
+ const phoff = @sizeOf(elf.Elf64_Ehdr);
+ const phdrs_size = self.phdrs.items.len * @sizeOf(elf.Elf64_Phdr);
+ log.debug("writing program headers from 0x{x} to 0x{x}", .{ phoff, phoff + phdrs_size });
+ try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.phdrs.items), phoff);
+}
+
+fn writeHeader(self: *Elf) !void {
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
var index: usize = 0;
@@ -2532,7 +2518,11 @@ fn writeElfHeader(self: *Elf) !void {
const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
- const phdr_table_offset = self.phdrs.items[self.phdr_table_index.?].p_offset;
+ // TODO
+ const phdr_table_offset = if (self.phdr_table_index) |ind|
+ self.phdrs.items[ind].p_offset
+ else
+ @sizeOf(elf.Elf64_Ehdr);
switch (self.ptr_width) {
.p32 => {
mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);
@@ -3401,13 +3391,7 @@ fn initSections(self: *Elf) !void {
};
for (self.objects.items) |index| {
- const object = self.file(index).?.object;
- for (object.atoms.items) |atom_index| {
- const atom_ptr = self.atom(atom_index) orelse continue;
- if (!atom_ptr.flags.alive) continue;
- const shdr = atom_ptr.inputShdr(self);
- atom_ptr.output_section_index = try object.initOutputSection(self, shdr);
- }
+ try self.file(index).?.object.initOutputSections(self);
}
if (self.got.entries.items.len > 0 and self.got_section_index == null) {
@@ -3525,14 +3509,6 @@ fn sortSections(self: *Elf) !void {
self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
}
- for (self.objects.items) |index| {
- for (self.file(index).?.atoms()) |atom_index| {
- const atom_ptr = self.atom(atom_index) orelse continue;
- if (!atom_ptr.flags.alive) continue;
- atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
- }
- }
-
for (&[_]*?u16{
&self.eh_frame_section_index,
&self.eh_frame_hdr_section_index,
@@ -3891,6 +3867,31 @@ fn allocateAtoms(self: *Elf) void {
}
}
+fn writeAtoms(self: *Elf) !void {
+ const gpa = self.base.allocator;
+ for (self.shdrs.items, 0..) |shdr, shndx| {
+ if (shdr.sh_type == elf.SHT_NULL) continue;
+ if (shdr.sh_type == elf.SHT_NOBITS) continue;
+
+ log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});
+
+ const buffer = try gpa.alloc(u8, shdr.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 (self.objects.items) |index| {
+ try self.file(index).?.object.writeAtoms(self, @intCast(shndx), buffer);
+ }
+
+ try self.base.file.?.pwriteAll(buffer, shdr.sh_offset);
+ }
+}
+
fn updateSymtabSize(self: *Elf) !void {
var sizes = SymtabSize{};