| ... | @@ -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); |
| 225 | | 221 | |
| ... | @@ -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.ro | 641 | .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; |
| 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 | 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 | } |
| 1390 | | 1361 | |
| 1391 | if (self.isStaticLib()) return self.flushStaticLib(comp); | 1362 | if (self.isStaticLib()) return self.flushStaticLib(); |
| 1392 | | 1363 | |
| 1393 | // Init all objects | 1364 | // 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(); |
| 1434 | | 1405 | |
| 1435 | if (self.isObject()) return self.flushObject(comp); | 1406 | if (self.isObject()) return self.flushObject(); |
| 1436 | | 1407 | |
| 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 | } |
| 1529 | | 1500 | |
| 1530 | pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void { | 1501 | pub fn flushStaticLib(self: *Elf) link.File.FlushError!void { |
| 1531 | _ = comp; | | |
| 1532 | const gpa = self.base.allocator; | 1502 | const gpa = self.base.allocator; |
| 1533 | | 1503 | |
| 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(); |
| 1545 | | 1515 | |
| ... | @@ -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 | } |
| 1641 | | 1611 | |
| 1642 | pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void { | 1612 | pub 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(); |
| 1653 | | 1614 | |
| 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(); |
| 1657 | | 1621 | |
| | 1622 | try self.allocateAllocSectionsObject(); |
| 1658 | try self.allocateNonAllocSections(); | 1623 | try self.allocateNonAllocSections(); |
| | 1624 | self.allocateAtoms(); |
| 1659 | | 1625 | |
| 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 | } |
| 1663 | | 1629 | |
| | 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 | } |
| 1668 | | 1635 | |
| ... | @@ -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 | } |
| 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 | fn initSymtab(self: *Elf) !void { | 3456 | fn 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 | } |
| 3984 | | 3977 | |
| 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 | } |
| 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 | fn updateShStrtabSize(self: *Elf) void { | 4088 | fn 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 | } |
| 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 | /// Allocates non-alloc sections (debug info, symtabs, etc.). | 4323 | /// Allocates non-alloc sections (debug info, symtabs, etc.). |
| 4298 | fn allocateNonAllocSections(self: *Elf) !void { | 4324 | fn 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 | } |
| 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 | fn updateSymtabSize(self: *Elf) void { | 4574 | fn updateSymtabSize(self: *Elf) void { |
| 4488 | var sizes = SymtabSize{}; | 4575 | var sizes = SymtabSize{}; |
| 4489 | | 4576 | |
| ... | @@ -4567,10 +4654,6 @@ fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void { | ... | @@ -4567,10 +4654,6 @@ fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void { |
| 4567 | fn writeSyntheticSections(self: *Elf) !void { | 4654 | fn writeSyntheticSections(self: *Elf) !void { |
| 4568 | const gpa = self.base.allocator; | 4655 | const gpa = self.base.allocator; |
| 4569 | | 4656 | |
| 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 | } |
| 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 | fn writeShStrtab(self: *Elf) !void { | 4808 | fn 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]; |