authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-03 11:33:03+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:04+02:00
log53340544c6666d9d35463f509fbe0416f607c91c
tree7ea4b34f28e779e6538deb70746603089e5a4162
parent1b70ad622bd6dbc776563656a6aaee94d69c66ea

elf: get hello-world with LLVM in Zig working


2 files changed, 93 insertions(+), 45 deletions(-)

src/link/Elf.zig+45-44
......@@ -1245,6 +1245,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12451245 // Generate and emit non-incremental sections.
12461246 try self.initSections();
12471247 try self.sortSections();
1248 for (self.objects.items) |index| {
1249 try self.file(index).?.object.addAtomsToOutputSections(self);
1250 }
12481251 try self.updateSectionSizes();
12491252
12501253 try self.allocateSections();
......@@ -1424,7 +1427,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14241427 phdr_table_load.p_filesz = 0;
14251428
14261429 self.phdr_table_dirty = false;
1427 }
1430 } else try self.writePhdrs();
14281431
14291432 if (self.shdr_table_dirty) {
14301433 const shsize: u64 = switch (self.ptr_width) {
......@@ -1476,8 +1479,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14761479 self.shdr_table_dirty = false;
14771480 }
14781481
1482 try self.writeAtoms();
14791483 try self.writeSyntheticSections();
1480 try self.writeObjects();
14811484
14821485 if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {
14831486 log.debug("flushing. no_entry_point_found = true", .{});
......@@ -1485,7 +1488,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14851488 } else {
14861489 log.debug("flushing. no_entry_point_found = false", .{});
14871490 self.error_flags.no_entry_point_found = false;
1488 try self.writeElfHeader();
1491 try self.writeHeader();
14891492 }
14901493
14911494 // Dump the state for easy debugging.
......@@ -1756,30 +1759,6 @@ fn scanRelocs(self: *Elf) !void {
17561759 }
17571760}
17581761
1759fn writeObjects(self: *Elf) !void {
1760 const gpa = self.base.allocator;
1761
1762 for (self.objects.items) |index| {
1763 const object = self.file(index).?.object;
1764 for (object.atoms.items) |atom_index| {
1765 const atom_ptr = self.atom(atom_index) orelse continue;
1766 if (!atom_ptr.flags.alive) continue;
1767
1768 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
1769 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1770 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections
1771
1772 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1773 log.debug("writing atom({d}) at 0x{x}", .{ atom_ptr.atom_index, file_offset });
1774 const code = try object.codeDecompressAlloc(self, atom_ptr.atom_index);
1775 defer gpa.free(code);
1776
1777 try atom_ptr.resolveRelocs(self, code);
1778 try self.base.file.?.pwriteAll(code, file_offset);
1779 }
1780 }
1781}
1782
17831762fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
17841763 const tracy = trace(@src());
17851764 defer tracy.end();
......@@ -2480,7 +2459,14 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64)
24802459 }
24812460}
24822461
2483fn writeElfHeader(self: *Elf) !void {
2462fn writePhdrs(self: *Elf) !void {
2463 const phoff = @sizeOf(elf.Elf64_Ehdr);
2464 const phdrs_size = self.phdrs.items.len * @sizeOf(elf.Elf64_Phdr);
2465 log.debug("writing program headers from 0x{x} to 0x{x}", .{ phoff, phoff + phdrs_size });
2466 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.phdrs.items), phoff);
2467}
2468
2469fn writeHeader(self: *Elf) !void {
24842470 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
24852471
24862472 var index: usize = 0;
......@@ -2532,7 +2518,11 @@ fn writeElfHeader(self: *Elf) !void {
25322518
25332519 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
25342520
2535 const phdr_table_offset = self.phdrs.items[self.phdr_table_index.?].p_offset;
2521 // TODO
2522 const phdr_table_offset = if (self.phdr_table_index) |ind|
2523 self.phdrs.items[ind].p_offset
2524 else
2525 @sizeOf(elf.Elf64_Ehdr);
25362526 switch (self.ptr_width) {
25372527 .p32 => {
25382528 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);
......@@ -3401,13 +3391,7 @@ fn initSections(self: *Elf) !void {
34013391 };
34023392
34033393 for (self.objects.items) |index| {
3404 const object = self.file(index).?.object;
3405 for (object.atoms.items) |atom_index| {
3406 const atom_ptr = self.atom(atom_index) orelse continue;
3407 if (!atom_ptr.flags.alive) continue;
3408 const shdr = atom_ptr.inputShdr(self);
3409 atom_ptr.output_section_index = try object.initOutputSection(self, shdr);
3410 }
3394 try self.file(index).?.object.initOutputSections(self);
34113395 }
34123396
34133397 if (self.got.entries.items.len > 0 and self.got_section_index == null) {
......@@ -3525,14 +3509,6 @@ fn sortSections(self: *Elf) !void {
35253509 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
35263510 }
35273511
3528 for (self.objects.items) |index| {
3529 for (self.file(index).?.atoms()) |atom_index| {
3530 const atom_ptr = self.atom(atom_index) orelse continue;
3531 if (!atom_ptr.flags.alive) continue;
3532 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
3533 }
3534 }
3535
35363512 for (&[_]*?u16{
35373513 &self.eh_frame_section_index,
35383514 &self.eh_frame_hdr_section_index,
......@@ -3891,6 +3867,31 @@ fn allocateAtoms(self: *Elf) void {
38913867 }
38923868}
38933869
3870fn writeAtoms(self: *Elf) !void {
3871 const gpa = self.base.allocator;
3872 for (self.shdrs.items, 0..) |shdr, shndx| {
3873 if (shdr.sh_type == elf.SHT_NULL) continue;
3874 if (shdr.sh_type == elf.SHT_NOBITS) continue;
3875
3876 log.debug("writing atoms in '{s}' section", .{self.shstrtab.getAssumeExists(shdr.sh_name)});
3877
3878 const buffer = try gpa.alloc(u8, shdr.sh_size);
3879 defer gpa.free(buffer);
3880 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
3881 shdr.sh_flags & elf.SHF_EXECINSTR != 0)
3882 0xcc // int3
3883 else
3884 0;
3885 @memset(buffer, padding_byte);
3886
3887 for (self.objects.items) |index| {
3888 try self.file(index).?.object.writeAtoms(self, @intCast(shndx), buffer);
3889 }
3890
3891 try self.base.file.?.pwriteAll(buffer, shdr.sh_offset);
3892 }
3893}
3894
38943895fn updateSymtabSize(self: *Elf) !void {
38953896 var sizes = SymtabSize{};
38963897
src/link/Elf/Object.zig+48-1
......@@ -20,6 +20,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
2020alive: bool = true,
2121num_dynrelocs: u32 = 0,
2222
23output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},
2324output_symtab_size: Elf.SymtabSize = .{},
2425
2526pub fn isObject(file: std.fs.File) bool {
......@@ -42,6 +43,10 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
4243 self.comdat_groups.deinit(allocator);
4344 self.fdes.deinit(allocator);
4445 self.cies.deinit(allocator);
46 for (self.output_sections.values()) |*list| {
47 list.deinit(allocator);
48 }
49 self.output_sections.deinit(allocator);
4550}
4651
4752pub fn parse(self: *Object, elf_file: *Elf) !void {
......@@ -193,7 +198,7 @@ fn addAtom(
193198 }
194199}
195200
196pub fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
201fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
197202 const name = blk: {
198203 const name = self.strings.getAssumeExists(shdr.sh_name);
199204 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
......@@ -601,6 +606,30 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
601606 }
602607}
603608
609pub fn initOutputSections(self: Object, elf_file: *Elf) !void {
610 for (self.atoms.items) |atom_index| {
611 const atom = elf_file.atom(atom_index) orelse continue;
612 if (!atom.flags.alive) continue;
613 const shdr = atom.inputShdr(elf_file);
614 _ = try self.initOutputSection(elf_file, shdr);
615 }
616}
617
618pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
619 for (self.atoms.items) |atom_index| {
620 const atom = elf_file.atom(atom_index) orelse continue;
621 if (!atom.flags.alive) continue;
622 const shdr = atom.inputShdr(elf_file);
623 atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
624
625 if (shdr.sh_type == elf.SHT_NOBITS) continue;
626 const gpa = elf_file.base.allocator;
627 const gop = try self.output_sections.getOrPut(gpa, atom.output_section_index);
628 if (!gop.found_existing) gop.value_ptr.* = .{};
629 try gop.value_ptr.append(gpa, atom_index);
630 }
631}
632
604633pub fn updateSectionSizes(self: Object, elf_file: *Elf) void {
605634 for (self.atoms.items) |atom_index| {
606635 const atom = elf_file.atom(atom_index) orelse continue;
......@@ -640,6 +669,24 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
640669 }
641670}
642671
672pub fn writeAtoms(self: Object, elf_file: *Elf, output_section_index: u16, buffer: []u8) !void {
673 const gpa = elf_file.base.allocator;
674 const atom_list = self.output_sections.get(output_section_index) orelse return;
675 const shdr = elf_file.shdrs.items[output_section_index];
676 for (atom_list.items) |atom_index| {
677 const atom = elf_file.atom(atom_index).?;
678 assert(atom.flags.alive);
679 const offset = atom.value - shdr.sh_addr;
680 log.debug("writing atom({d}) at 0x{x}", .{ atom_index, shdr.sh_offset + offset });
681 // TODO decompress directly into provided buffer
682 const out_code = buffer[offset..][0..atom.size];
683 const in_code = try self.codeDecompressAlloc(elf_file, atom_index);
684 defer gpa.free(in_code);
685 @memcpy(out_code, in_code);
686 try atom.resolveRelocs(elf_file, out_code);
687 }
688}
689
643690pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
644691 for (self.locals()) |local_index| {
645692 const local = elf_file.symbol(local_index);