| ... | ... | @@ -216,10 +216,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 216 | 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 | 220 | errdefer if (self.base.intermediary_basename) |path| allocator.free(path); |
| 225 | 221 | |
| ... | ... | @@ -642,7 +638,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 642 | 638 | .name = ".data.rel.ro.zig", |
| 643 | 639 | .type = elf.SHT_PROGBITS, |
| 644 | 640 | .addralign = 1, |
| 645 | | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro |
| 641 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, |
| 646 | 642 | .offset = std.math.maxInt(u64), |
| 647 | 643 | }); |
| 648 | 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 | 938 | } else null; |
| 943 | 939 | const gc_sections = self.base.options.gc_sections orelse false; |
| 944 | 940 | |
| 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 | 941 | var csu = try CsuObjects.init(arena, self.base.options, comp); |
| 971 | 942 | const compiler_rt_path: ?[]const u8 = blk: { |
| 972 | 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 | 1359 | try self.handleAndReportParseError(obj.path, err, &parse_ctx); |
| 1389 | 1360 | } |
| 1390 | 1361 | |
| 1391 | | if (self.isStaticLib()) return self.flushStaticLib(comp); |
| 1362 | if (self.isStaticLib()) return self.flushStaticLib(); |
| 1392 | 1363 | |
| 1393 | 1364 | // Init all objects |
| 1394 | 1365 | for (self.objects.items) |index| { |
| ... | ... | @@ -1432,7 +1403,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1432 | 1403 | self.resolveSymbols(); |
| 1433 | 1404 | self.markEhFrameAtomsDead(); |
| 1434 | 1405 | |
| 1435 | | if (self.isObject()) return self.flushObject(comp); |
| 1406 | if (self.isObject()) return self.flushObject(); |
| 1436 | 1407 | |
| 1437 | 1408 | try self.convertCommonSymbols(); |
| 1438 | 1409 | self.markImportsExports(); |
| ... | ... | @@ -1527,8 +1498,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1527 | 1498 | } |
| 1528 | 1499 | } |
| 1529 | 1500 | |
| 1530 | | pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void { |
| 1531 | | _ = comp; |
| 1501 | pub fn flushStaticLib(self: *Elf) link.File.FlushError!void { |
| 1532 | 1502 | const gpa = self.base.allocator; |
| 1533 | 1503 | |
| 1534 | 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 | 1509 | try self.initSymtab(); |
| 1540 | 1510 | try self.initShStrtab(); |
| 1541 | 1511 | try self.sortShdrs(); |
| 1542 | | zig_object.updateRelaSectionSizes(self); |
| 1512 | zig_object.updateRelaSectionsSizes(self); |
| 1543 | 1513 | self.updateSymtabSizeObject(zig_object); |
| 1544 | 1514 | self.updateShStrtabSize(); |
| 1545 | 1515 | |
| ... | ... | @@ -1639,30 +1609,27 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void |
| 1639 | 1609 | try self.base.file.?.pwriteAll(buffer.items, 0); |
| 1640 | 1610 | } |
| 1641 | 1611 | |
| 1642 | | pub fn flushObject(self: *Elf, comp: *Compilation) 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 | | |
| 1612 | pub fn flushObject(self: *Elf) link.File.FlushError!void { |
| 1652 | 1613 | self.claimUnresolvedObject(); |
| 1653 | 1614 | |
| 1654 | | try self.initSections(); |
| 1615 | try self.initSectionsObject(); |
| 1655 | 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(); |
| 1657 | 1621 | |
| 1622 | try self.allocateAllocSectionsObject(); |
| 1658 | 1623 | try self.allocateNonAllocSections(); |
| 1624 | self.allocateAtoms(); |
| 1659 | 1625 | |
| 1660 | 1626 | if (build_options.enable_logging) { |
| 1661 | 1627 | state_log.debug("{}", .{self.dumpState()}); |
| 1662 | 1628 | } |
| 1663 | 1629 | |
| 1630 | try self.writeAtomsObject(); |
| 1631 | try self.writeSyntheticSectionsObject(); |
| 1664 | 1632 | try self.writeShdrTable(); |
| 1665 | | try self.writeSyntheticSections(); |
| 1666 | 1633 | try self.writeElfHeader(); |
| 1667 | 1634 | } |
| 1668 | 1635 | |
| ... | ... | @@ -3460,6 +3427,32 @@ fn initSections(self: *Elf) !void { |
| 3460 | 3427 | try self.initShStrtab(); |
| 3461 | 3428 | } |
| 3462 | 3429 | |
| 3430 | fn 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 | |
| 3463 | 3456 | fn initSymtab(self: *Elf) !void { |
| 3464 | 3457 | const small_ptr = switch (self.ptr_width) { |
| 3465 | 3458 | .p32 => true, |
| ... | ... | @@ -3982,10 +3975,6 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3982 | 3975 | } |
| 3983 | 3976 | } |
| 3984 | 3977 | |
| 3985 | | if (self.zigObjectPtr()) |zig_object| { |
| 3986 | | zig_object.updateRelaSectionSizes(self); |
| 3987 | | } |
| 3988 | | |
| 3989 | 3978 | if (self.eh_frame_section_index) |index| { |
| 3990 | 3979 | self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); |
| 3991 | 3980 | } |
| ... | ... | @@ -4065,6 +4054,37 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4065 | 4054 | self.updateShStrtabSize(); |
| 4066 | 4055 | } |
| 4067 | 4056 | |
| 4057 | fn 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 | |
| 4068 | 4088 | fn updateShStrtabSize(self: *Elf) void { |
| 4069 | 4089 | if (self.shstrtab_section_index) |index| { |
| 4070 | 4090 | self.shdrs.items[index].sh_size = self.shstrtab.items.len; |
| ... | ... | @@ -4294,6 +4314,12 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4294 | 4314 | } |
| 4295 | 4315 | } |
| 4296 | 4316 | |
| 4317 | /// Allocates alloc sections when merging relocatable objects files together. |
| 4318 | fn allocateAllocSectionsObject(self: *Elf) !void { |
| 4319 | _ = self; |
| 4320 | @panic("TODO"); |
| 4321 | } |
| 4322 | |
| 4297 | 4323 | /// Allocates non-alloc sections (debug info, symtabs, etc.). |
| 4298 | 4324 | fn allocateNonAllocSections(self: *Elf) !void { |
| 4299 | 4325 | for (self.shdrs.items, 0..) |*shdr, shndx| { |
| ... | ... | @@ -4484,6 +4510,67 @@ fn writeAtoms(self: *Elf) !void { |
| 4484 | 4510 | try self.reportUndefined(&undefs); |
| 4485 | 4511 | } |
| 4486 | 4512 | |
| 4513 | fn 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 | |
| 4487 | 4574 | fn updateSymtabSize(self: *Elf) void { |
| 4488 | 4575 | var sizes = SymtabSize{}; |
| 4489 | 4576 | |
| ... | ... | @@ -4567,10 +4654,6 @@ fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void { |
| 4567 | 4654 | fn writeSyntheticSections(self: *Elf) !void { |
| 4568 | 4655 | const gpa = self.base.allocator; |
| 4569 | 4656 | |
| 4570 | | if (self.zigObjectPtr()) |zig_object| { |
| 4571 | | try zig_object.writeRelaSections(self); |
| 4572 | | } |
| 4573 | | |
| 4574 | 4657 | if (self.interp_section_index) |shndx| { |
| 4575 | 4658 | const shdr = self.shdrs.items[shndx]; |
| 4576 | 4659 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| ... | ... | @@ -4698,6 +4781,30 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 4698 | 4781 | try self.writeShStrtab(); |
| 4699 | 4782 | } |
| 4700 | 4783 | |
| 4784 | fn 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 | |
| 4701 | 4808 | fn writeShStrtab(self: *Elf) !void { |
| 4702 | 4809 | if (self.shstrtab_section_index) |index| { |
| 4703 | 4810 | const shdr = self.shdrs.items[index]; |