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...@@ -1245,6 +1245,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1245 // Generate and emit non-incremental sections.1245 // Generate and emit non-incremental sections.
1246 try self.initSections();1246 try self.initSections();
1247 try self.sortSections();1247 try self.sortSections();
1248 for (self.objects.items) |index| {
1249 try self.file(index).?.object.addAtomsToOutputSections(self);
1250 }
1248 try self.updateSectionSizes();1251 try self.updateSectionSizes();
12491252
1250 try self.allocateSections();1253 try self.allocateSections();
...@@ -1424,7 +1427,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1424,7 +1427,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1424 phdr_table_load.p_filesz = 0;1427 phdr_table_load.p_filesz = 0;
14251428
1426 self.phdr_table_dirty = false;1429 self.phdr_table_dirty = false;
1427 }1430 } else try self.writePhdrs();
14281431
1429 if (self.shdr_table_dirty) {1432 if (self.shdr_table_dirty) {
1430 const shsize: u64 = switch (self.ptr_width) {1433 const shsize: u64 = switch (self.ptr_width) {
...@@ -1476,8 +1479,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1476,8 +1479,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1476 self.shdr_table_dirty = false;1479 self.shdr_table_dirty = false;
1477 }1480 }
14781481
1482 try self.writeAtoms();
1479 try self.writeSyntheticSections();1483 try self.writeSyntheticSections();
1480 try self.writeObjects();
14811484
1482 if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {1485 if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {
1483 log.debug("flushing. no_entry_point_found = true", .{});1486 log.debug("flushing. no_entry_point_found = true", .{});
...@@ -1485,7 +1488,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1485,7 +1488,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1485 } else {1488 } else {
1486 log.debug("flushing. no_entry_point_found = false", .{});1489 log.debug("flushing. no_entry_point_found = false", .{});
1487 self.error_flags.no_entry_point_found = false;1490 self.error_flags.no_entry_point_found = false;
1488 try self.writeElfHeader();1491 try self.writeHeader();
1489 }1492 }
14901493
1491 // Dump the state for easy debugging.1494 // Dump the state for easy debugging.
...@@ -1756,30 +1759,6 @@ fn scanRelocs(self: *Elf) !void {...@@ -1756,30 +1759,6 @@ fn scanRelocs(self: *Elf) !void {
1756 }1759 }
1757}1760}
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
1783fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {1762fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
1784 const tracy = trace(@src());1763 const tracy = trace(@src());
1785 defer tracy.end();1764 defer tracy.end();
...@@ -2480,7 +2459,14 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64)...@@ -2480,7 +2459,14 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64)
2480 }2459 }
2481}2460}
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 {
2484 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;2470 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
24852471
2486 var index: usize = 0;2472 var index: usize = 0;
...@@ -2532,7 +2518,11 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2532,7 +2518,11 @@ fn writeElfHeader(self: *Elf) !void {
25322518
2533 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;2519 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);
2536 switch (self.ptr_width) {2526 switch (self.ptr_width) {
2537 .p32 => {2527 .p32 => {
2538 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);2528 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);
...@@ -3401,13 +3391,7 @@ fn initSections(self: *Elf) !void {...@@ -3401,13 +3391,7 @@ fn initSections(self: *Elf) !void {
3401 };3391 };
34023392
3403 for (self.objects.items) |index| {3393 for (self.objects.items) |index| {
3404 const object = self.file(index).?.object;3394 try self.file(index).?.object.initOutputSections(self);
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 }
3411 }3395 }
34123396
3413 if (self.got.entries.items.len > 0 and self.got_section_index == null) {3397 if (self.got.entries.items.len > 0 and self.got_section_index == null) {
...@@ -3525,14 +3509,6 @@ fn sortSections(self: *Elf) !void {...@@ -3525,14 +3509,6 @@ fn sortSections(self: *Elf) !void {
3525 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);3509 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
3526 }3510 }
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
3536 for (&[_]*?u16{3512 for (&[_]*?u16{
3537 &self.eh_frame_section_index,3513 &self.eh_frame_section_index,
3538 &self.eh_frame_hdr_section_index,3514 &self.eh_frame_hdr_section_index,
...@@ -3891,6 +3867,31 @@ fn allocateAtoms(self: *Elf) void {...@@ -3891,6 +3867,31 @@ fn allocateAtoms(self: *Elf) void {
3891 }3867 }
3892}3868}
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
3894fn updateSymtabSize(self: *Elf) !void {3895fn updateSymtabSize(self: *Elf) !void {
3895 var sizes = SymtabSize{};3896 var sizes = SymtabSize{};
38963897
src/link/Elf/Object.zig+48-1
...@@ -20,6 +20,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},...@@ -20,6 +20,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
20alive: bool = true,20alive: bool = true,
21num_dynrelocs: u32 = 0,21num_dynrelocs: u32 = 0,
2222
23output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},
23output_symtab_size: Elf.SymtabSize = .{},24output_symtab_size: Elf.SymtabSize = .{},
2425
25pub fn isObject(file: std.fs.File) bool {26pub fn isObject(file: std.fs.File) bool {
...@@ -42,6 +43,10 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -42,6 +43,10 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
42 self.comdat_groups.deinit(allocator);43 self.comdat_groups.deinit(allocator);
43 self.fdes.deinit(allocator);44 self.fdes.deinit(allocator);
44 self.cies.deinit(allocator);45 self.cies.deinit(allocator);
46 for (self.output_sections.values()) |*list| {
47 list.deinit(allocator);
48 }
49 self.output_sections.deinit(allocator);
45}50}
4651
47pub fn parse(self: *Object, elf_file: *Elf) !void {52pub fn parse(self: *Object, elf_file: *Elf) !void {
...@@ -193,7 +198,7 @@ fn addAtom(...@@ -193,7 +198,7 @@ fn addAtom(
193 }198 }
194}199}
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 {
197 const name = blk: {202 const name = blk: {
198 const name = self.strings.getAssumeExists(shdr.sh_name);203 const name = self.strings.getAssumeExists(shdr.sh_name);
199 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;204 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
...@@ -601,6 +606,30 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -601,6 +606,30 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
601 }606 }
602}607}
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
604pub fn updateSectionSizes(self: Object, elf_file: *Elf) void {633pub fn updateSectionSizes(self: Object, elf_file: *Elf) void {
605 for (self.atoms.items) |atom_index| {634 for (self.atoms.items) |atom_index| {
606 const atom = elf_file.atom(atom_index) orelse continue;635 const atom = elf_file.atom(atom_index) orelse continue;
...@@ -640,6 +669,24 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {...@@ -640,6 +669,24 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
640 }669 }
641}670}
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
643pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {690pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
644 for (self.locals()) |local_index| {691 for (self.locals()) |local_index| {
645 const local = elf_file.symbol(local_index);692 const local = elf_file.symbol(local_index);