authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-07 11:19:55+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-07 11:19:55+01:00
log3df53d1722da9e4fcc8606315c68ffb884a0dd5a
tree658b656d974ee1f8671bfcd4f7b7dba1d8b78722
parentb3462b7cec9931cd3747f10714954eb8efe00c04

elf: create skeleton of required changes for supporting -r mode


3 files changed, 179 insertions(+), 57 deletions(-)

src/link/Elf.zig+163-56
...@@ -216,10 +216,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -216,10 +216,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
216 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),216 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
217 });217 });
218 }218 }
219 if (is_obj) {
220 // TODO until we implement -r option, we don't want to open a file at this stage.
221 return self;
222 }
223 }219 }
224 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);220 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);
225221
...@@ -642,7 +638,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -642,7 +638,7 @@ pub fn initMetadata(self: *Elf) !void {
642 .name = ".data.rel.ro.zig",638 .name = ".data.rel.ro.zig",
643 .type = elf.SHT_PROGBITS,639 .type = elf.SHT_PROGBITS,
644 .addralign = 1,640 .addralign = 1,
645 .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro641 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
646 .offset = std.math.maxInt(u64),642 .offset = std.math.maxInt(u64),
647 });643 });
648 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];644 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
...@@ -942,31 +938,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -942,31 +938,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
942 } else null;938 } else null;
943 const gc_sections = self.base.options.gc_sections orelse false;939 const gc_sections = self.base.options.gc_sections orelse false;
944940
945 if (self.isObject() and self.zig_object_index == null) {
946 // TODO this will become -r route I guess. For now, just copy the object file.
947 const the_object_path = blk: {
948 if (self.base.options.objects.len != 0) {
949 break :blk self.base.options.objects[0].path;
950 }
951
952 if (comp.c_object_table.count() != 0)
953 break :blk comp.c_object_table.keys()[0].status.success.object_path;
954
955 if (module_obj_path) |p|
956 break :blk p;
957
958 // TODO I think this is unreachable. Audit this situation when solving the above TODO
959 // regarding eliding redundant object -> object transformations.
960 return error.NoObjectsToLink;
961 };
962 // This can happen when using --enable-cache and using the stage1 backend. In this case
963 // we can skip the file copy.
964 if (!mem.eql(u8, the_object_path, full_out_path)) {
965 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
966 }
967 return;
968 }
969
970 var csu = try CsuObjects.init(arena, self.base.options, comp);941 var csu = try CsuObjects.init(arena, self.base.options, comp);
971 const compiler_rt_path: ?[]const u8 = blk: {942 const compiler_rt_path: ?[]const u8 = blk: {
972 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;943 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
...@@ -1388,7 +1359,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1388,7 +1359,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1388 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1359 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1389 }1360 }
13901361
1391 if (self.isStaticLib()) return self.flushStaticLib(comp);1362 if (self.isStaticLib()) return self.flushStaticLib();
13921363
1393 // Init all objects1364 // Init all objects
1394 for (self.objects.items) |index| {1365 for (self.objects.items) |index| {
...@@ -1432,7 +1403,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1432,7 +1403,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1432 self.resolveSymbols();1403 self.resolveSymbols();
1433 self.markEhFrameAtomsDead();1404 self.markEhFrameAtomsDead();
14341405
1435 if (self.isObject()) return self.flushObject(comp);1406 if (self.isObject()) return self.flushObject();
14361407
1437 try self.convertCommonSymbols();1408 try self.convertCommonSymbols();
1438 self.markImportsExports();1409 self.markImportsExports();
...@@ -1527,8 +1498,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1527,8 +1498,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1527 }1498 }
1528}1499}
15291500
1530pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void {1501pub fn flushStaticLib(self: *Elf) link.File.FlushError!void {
1531 _ = comp;
1532 const gpa = self.base.allocator;1502 const gpa = self.base.allocator;
15331503
1534 // First, we flush relocatable object file generated with our backends.1504 // First, we flush relocatable object file generated with our backends.
...@@ -1539,7 +1509,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void...@@ -1539,7 +1509,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
1539 try self.initSymtab();1509 try self.initSymtab();
1540 try self.initShStrtab();1510 try self.initShStrtab();
1541 try self.sortShdrs();1511 try self.sortShdrs();
1542 zig_object.updateRelaSectionSizes(self);1512 zig_object.updateRelaSectionsSizes(self);
1543 self.updateSymtabSizeObject(zig_object);1513 self.updateSymtabSizeObject(zig_object);
1544 self.updateShStrtabSize();1514 self.updateShStrtabSize();
15451515
...@@ -1639,30 +1609,27 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void...@@ -1639,30 +1609,27 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
1639 try self.base.file.?.pwriteAll(buffer.items, 0);1609 try self.base.file.?.pwriteAll(buffer.items, 0);
1640}1610}
16411611
1642pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {1612pub fn flushObject(self: *Elf) link.File.FlushError!void {
1643 _ = comp;
1644
1645 if (self.objects.items.len > 0) {
1646 var err = try self.addErrorWithNotes(1);
1647 try err.addMsg(self, "fatal linker error: too many input positionals", .{});
1648 try err.addNote(self, "TODO implement '-r' option", .{});
1649 return;
1650 }
1651
1652 self.claimUnresolvedObject();1613 self.claimUnresolvedObject();
16531614
1654 try self.initSections();1615 try self.initSectionsObject();
1655 try self.sortShdrs();1616 try self.sortShdrs();
1656 try self.updateSectionSizes();1617 for (self.objects.items) |index| {
1618 try self.file(index).?.object.addAtomsToOutputSections(self);
1619 }
1620 try self.updateSectionSizesObject();
16571621
1622 try self.allocateAllocSectionsObject();
1658 try self.allocateNonAllocSections();1623 try self.allocateNonAllocSections();
1624 self.allocateAtoms();
16591625
1660 if (build_options.enable_logging) {1626 if (build_options.enable_logging) {
1661 state_log.debug("{}", .{self.dumpState()});1627 state_log.debug("{}", .{self.dumpState()});
1662 }1628 }
16631629
1630 try self.writeAtomsObject();
1631 try self.writeSyntheticSectionsObject();
1664 try self.writeShdrTable();1632 try self.writeShdrTable();
1665 try self.writeSyntheticSections();
1666 try self.writeElfHeader();1633 try self.writeElfHeader();
1667}1634}
16681635
...@@ -3460,6 +3427,32 @@ fn initSections(self: *Elf) !void {...@@ -3460,6 +3427,32 @@ fn initSections(self: *Elf) !void {
3460 try self.initShStrtab();3427 try self.initShStrtab();
3461}3428}
34623429
3430fn initSectionsObject(self: *Elf) !void {
3431 const ptr_size = self.ptrWidthBytes();
3432
3433 for (self.objects.items) |index| {
3434 const object = self.file(index).?.object;
3435 try object.initOutputSections(self);
3436 try object.initRelaSections(self);
3437 }
3438
3439 const needs_eh_frame = for (self.objects.items) |index| {
3440 if (self.file(index).?.object.cies.items.len > 0) break true;
3441 } else false;
3442 if (needs_eh_frame) {
3443 self.eh_frame_section_index = try self.addSection(.{
3444 .name = ".eh_frame",
3445 .type = elf.SHT_PROGBITS,
3446 .flags = elf.SHF_ALLOC,
3447 .addralign = ptr_size,
3448 .offset = std.math.maxInt(u64),
3449 });
3450 }
3451
3452 try self.initSymtab();
3453 try self.initShStrtab();
3454}
3455
3463fn initSymtab(self: *Elf) !void {3456fn initSymtab(self: *Elf) !void {
3464 const small_ptr = switch (self.ptr_width) {3457 const small_ptr = switch (self.ptr_width) {
3465 .p32 => true,3458 .p32 => true,
...@@ -3982,10 +3975,6 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3982,10 +3975,6 @@ fn updateSectionSizes(self: *Elf) !void {
3982 }3975 }
3983 }3976 }
39843977
3985 if (self.zigObjectPtr()) |zig_object| {
3986 zig_object.updateRelaSectionSizes(self);
3987 }
3988
3989 if (self.eh_frame_section_index) |index| {3978 if (self.eh_frame_section_index) |index| {
3990 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);3979 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
3991 }3980 }
...@@ -4065,6 +4054,37 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4065,6 +4054,37 @@ fn updateSectionSizes(self: *Elf) !void {
4065 self.updateShStrtabSize();4054 self.updateShStrtabSize();
4066}4055}
40674056
4057fn updateSectionSizesObject(self: *Elf) !void {
4058 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
4059 if (atom_list.items.len == 0) continue;
4060 const shdr = &self.shdrs.items[shndx];
4061 for (atom_list.items) |atom_index| {
4062 const atom_ptr = self.atom(atom_index) orelse continue;
4063 if (!atom_ptr.flags.alive) continue;
4064 const offset = atom_ptr.alignment.forward(shdr.sh_size);
4065 const padding = offset - shdr.sh_size;
4066 atom_ptr.value = offset;
4067 shdr.sh_size += padding + atom_ptr.size;
4068 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
4069 }
4070 }
4071
4072 if (self.zigObjectPtr()) |zig_object| {
4073 zig_object.updateRelaSectionsSizes(self);
4074 }
4075
4076 for (self.objects.items) |index| {
4077 self.file(index).?.object.updateRelaSectionsSizes(self);
4078 }
4079
4080 if (self.eh_frame_section_index) |index| {
4081 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
4082 }
4083
4084 self.updateSymtabSize();
4085 self.updateShStrtabSize();
4086}
4087
4068fn updateShStrtabSize(self: *Elf) void {4088fn updateShStrtabSize(self: *Elf) void {
4069 if (self.shstrtab_section_index) |index| {4089 if (self.shstrtab_section_index) |index| {
4070 self.shdrs.items[index].sh_size = self.shstrtab.items.len;4090 self.shdrs.items[index].sh_size = self.shstrtab.items.len;
...@@ -4294,6 +4314,12 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4294,6 +4314,12 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4294 }4314 }
4295}4315}
42964316
4317/// Allocates alloc sections when merging relocatable objects files together.
4318fn allocateAllocSectionsObject(self: *Elf) !void {
4319 _ = self;
4320 @panic("TODO");
4321}
4322
4297/// Allocates non-alloc sections (debug info, symtabs, etc.).4323/// Allocates non-alloc sections (debug info, symtabs, etc.).
4298fn allocateNonAllocSections(self: *Elf) !void {4324fn allocateNonAllocSections(self: *Elf) !void {
4299 for (self.shdrs.items, 0..) |*shdr, shndx| {4325 for (self.shdrs.items, 0..) |*shdr, shndx| {
...@@ -4484,6 +4510,67 @@ fn writeAtoms(self: *Elf) !void {...@@ -4484,6 +4510,67 @@ fn writeAtoms(self: *Elf) !void {
4484 try self.reportUndefined(&undefs);4510 try self.reportUndefined(&undefs);
4485}4511}
44864512
4513fn writeAtomsObject(self: *Elf) !void {
4514 const gpa = self.base.allocator;
4515
4516 // TODO iterate over `output_sections` directly
4517 for (self.shdrs.items, 0..) |shdr, shndx| {
4518 if (shdr.sh_type == elf.SHT_NULL) continue;
4519 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4520
4521 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
4522
4523 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
4524
4525 // TODO really, really handle debug section separately
4526 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
4527 const zig_object = self.zigObjectPtr().?;
4528 if (shndx == self.debug_info_section_index.?)
4529 break :blk zig_object.debug_info_section_zig_size;
4530 if (shndx == self.debug_abbrev_section_index.?)
4531 break :blk zig_object.debug_abbrev_section_zig_size;
4532 if (shndx == self.debug_str_section_index.?)
4533 break :blk zig_object.debug_str_section_zig_size;
4534 if (shndx == self.debug_aranges_section_index.?)
4535 break :blk zig_object.debug_aranges_section_zig_size;
4536 if (shndx == self.debug_line_section_index.?)
4537 break :blk zig_object.debug_line_section_zig_size;
4538 unreachable;
4539 } else 0;
4540 const sh_offset = shdr.sh_offset + base_offset;
4541 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
4542
4543 const buffer = try gpa.alloc(u8, sh_size);
4544 defer gpa.free(buffer);
4545 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
4546 shdr.sh_flags & elf.SHF_EXECINSTR != 0)
4547 0xcc // int3
4548 else
4549 0;
4550 @memset(buffer, padding_byte);
4551
4552 for (atom_list.items) |atom_index| {
4553 const atom_ptr = self.atom(atom_index).?;
4554 assert(atom_ptr.flags.alive);
4555
4556 const object = atom_ptr.file(self).?.object;
4557 const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse
4558 return error.Overflow;
4559 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
4560
4561 log.debug("writing atom({d}) at 0x{x}", .{ atom_index, sh_offset + offset });
4562
4563 // TODO decompress directly into provided buffer
4564 const out_code = buffer[offset..][0..size];
4565 const in_code = try object.codeDecompressAlloc(self, atom_index);
4566 defer gpa.free(in_code);
4567 @memcpy(out_code, in_code);
4568 }
4569
4570 try self.base.file.?.pwriteAll(buffer, sh_offset);
4571 }
4572}
4573
4487fn updateSymtabSize(self: *Elf) void {4574fn updateSymtabSize(self: *Elf) void {
4488 var sizes = SymtabSize{};4575 var sizes = SymtabSize{};
44894576
...@@ -4567,10 +4654,6 @@ fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void {...@@ -4567,10 +4654,6 @@ fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void {
4567fn writeSyntheticSections(self: *Elf) !void {4654fn writeSyntheticSections(self: *Elf) !void {
4568 const gpa = self.base.allocator;4655 const gpa = self.base.allocator;
45694656
4570 if (self.zigObjectPtr()) |zig_object| {
4571 try zig_object.writeRelaSections(self);
4572 }
4573
4574 if (self.interp_section_index) |shndx| {4657 if (self.interp_section_index) |shndx| {
4575 const shdr = self.shdrs.items[shndx];4658 const shdr = self.shdrs.items[shndx];
4576 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;4659 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
...@@ -4698,6 +4781,30 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4698,6 +4781,30 @@ fn writeSyntheticSections(self: *Elf) !void {
4698 try self.writeShStrtab();4781 try self.writeShStrtab();
4699}4782}
47004783
4784fn writeSyntheticSectionsObject(self: *Elf) !void {
4785 const gpa = self.base.allocator;
4786
4787 if (self.zigObjectPtr()) |zig_object| {
4788 try zig_object.writeRelaSections(self);
4789 }
4790
4791 for (self.objects.items) |index| {
4792 try self.file(index).?.object.writeRelaSections(self);
4793 }
4794
4795 if (self.eh_frame_section_index) |shndx| {
4796 const shdr = self.shdrs.items[shndx];
4797 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
4798 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
4799 defer buffer.deinit();
4800 try eh_frame.writeEhFrame(self, buffer.writer());
4801 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
4802 }
4803
4804 try self.writeSymtab();
4805 try self.writeShStrtab();
4806}
4807
4701fn writeShStrtab(self: *Elf) !void {4808fn writeShStrtab(self: *Elf) !void {
4702 if (self.shstrtab_section_index) |index| {4809 if (self.shstrtab_section_index) |index| {
4703 const shdr = self.shdrs.items[index];4810 const shdr = self.shdrs.items[index];
src/link/Elf/Object.zig+15
...@@ -654,6 +654,21 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {...@@ -654,6 +654,21 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
654 }654 }
655}655}
656656
657pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
658 _ = self;
659 _ = elf_file;
660}
661
662pub fn updateRelaSectionsSizes(self: Object, elf_file: *Elf) void {
663 _ = self;
664 _ = elf_file;
665}
666
667pub fn writeRelaSections(self: Object, elf_file: *Elf) !void {
668 _ = self;
669 _ = elf_file;
670}
671
657pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {672pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
658 const gpa = elf_file.base.allocator;673 const gpa = elf_file.base.allocator;
659 const start = self.first_global orelse self.symtab.items.len;674 const start = self.first_global orelse self.symtab.items.len;
src/link/Elf/ZigObject.zig+1-1
...@@ -549,7 +549,7 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {...@@ -549,7 +549,7 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
549 try writer.writeAll(contents);549 try writer.writeAll(contents);
550}550}
551551
552pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {552pub fn updateRelaSectionsSizes(self: ZigObject, elf_file: *Elf) void {
553 _ = self;553 _ = self;
554554
555 for (&[_]?u16{555 for (&[_]?u16{