| ... | ... | @@ -104,6 +104,10 @@ unnamed_const_atoms: UnnamedConstTable = .{}, |
| 104 | 104 | relocs: RelocTable = .{}, |
| 105 | 105 | |
| 106 | 106 | const Reloc = struct { |
| 107 | @"type": enum { |
| 108 | got_pcrel, |
| 109 | direct, |
| 110 | }, |
| 107 | 111 | target: SymbolWithLoc, |
| 108 | 112 | offset: u32, |
| 109 | 113 | addend: u32, |
| ... | ... | @@ -413,10 +417,11 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { |
| 413 | 417 | try self.decls.putNoClobber(gpa, decl_index, null); |
| 414 | 418 | } |
| 415 | 419 | |
| 416 | | fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 { |
| 420 | fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { |
| 417 | 421 | const tracy = trace(@src()); |
| 418 | 422 | defer tracy.end(); |
| 419 | 423 | |
| 424 | const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1; |
| 420 | 425 | const header = &self.sections.items(.header)[sect_id]; |
| 421 | 426 | const free_list = &self.sections.items(.free_list)[sect_id]; |
| 422 | 427 | const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; |
| ... | ... | @@ -580,18 +585,20 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 580 | 585 | |
| 581 | 586 | try self.managed_atoms.append(gpa, atom); |
| 582 | 587 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); |
| 588 | self.got_entries.getPtr(target).?.* = atom.sym_index; |
| 583 | 589 | |
| 584 | 590 | const sym = atom.getSymbolPtr(self); |
| 585 | | sym.value = try self.allocateAtom(atom, atom.size, atom.alignment, self.got_section_index.?); |
| 586 | 591 | sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1); |
| 592 | sym.value = try self.allocateAtom(atom, atom.size, atom.alignment); |
| 587 | 593 | |
| 588 | | log.debug("allocated {s} atom at 0x{x}", .{ atom.getName(self), sym.value }); |
| 594 | log.debug("allocated GOT atom at 0x{x}", .{sym.value}); |
| 589 | 595 | |
| 590 | 596 | const gop_relocs = try self.relocs.getOrPut(gpa, atom); |
| 591 | 597 | if (!gop_relocs.found_existing) { |
| 592 | 598 | gop_relocs.value_ptr.* = .{}; |
| 593 | 599 | } |
| 594 | 600 | try gop_relocs.value_ptr.append(gpa, .{ |
| 601 | .@"type" = .direct, |
| 595 | 602 | .target = target, |
| 596 | 603 | .offset = 0, |
| 597 | 604 | .addend = 0, |
| ... | ... | @@ -601,72 +608,98 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 601 | 608 | return atom; |
| 602 | 609 | } |
| 603 | 610 | |
| 604 | | fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 { |
| 611 | fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32) !u32 { |
| 605 | 612 | const sym = atom.getSymbol(self); |
| 606 | 613 | const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value; |
| 607 | 614 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); |
| 608 | 615 | if (!need_realloc) return sym.value; |
| 609 | | return self.allocateAtom(atom, new_atom_size, alignment, sect_id); |
| 616 | return self.allocateAtom(atom, new_atom_size, alignment); |
| 610 | 617 | } |
| 611 | 618 | |
| 612 | | fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32, sect_id: u16) void { |
| 619 | fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32) void { |
| 613 | 620 | _ = self; |
| 614 | 621 | _ = atom; |
| 615 | 622 | _ = new_block_size; |
| 616 | | _ = sect_id; |
| 617 | 623 | // TODO check the new capacity, and if it crosses the size threshold into a big enough |
| 618 | 624 | // capacity, insert a free list node for it. |
| 619 | 625 | } |
| 620 | 626 | |
| 621 | | fn writeAtom(self: *Coff, atom: *Atom, code: []const u8, sect_id: u16) !void { |
| 622 | | const section = self.sections.get(sect_id); |
| 627 | fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { |
| 623 | 628 | const sym = atom.getSymbol(self); |
| 629 | const section = self.sections.get(@enumToInt(sym.section_number) - 1); |
| 624 | 630 | const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; |
| 625 | | const resolved = try self.resolveRelocs(atom, code); |
| 626 | | defer self.base.allocator.free(resolved); |
| 627 | 631 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); |
| 628 | | try self.base.file.?.pwriteAll(resolved, file_offset); |
| 632 | try self.base.file.?.pwriteAll(code, file_offset); |
| 633 | try self.resolveRelocs(atom); |
| 629 | 634 | } |
| 630 | 635 | |
| 631 | 636 | fn writeGotAtom(self: *Coff, atom: *Atom) !void { |
| 632 | 637 | switch (self.ptr_width) { |
| 633 | 638 | .p32 => { |
| 634 | 639 | var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32); |
| 635 | | try self.writeAtom(atom, &buffer, self.got_section_index.?); |
| 640 | try self.writeAtom(atom, &buffer); |
| 636 | 641 | }, |
| 637 | 642 | .p64 => { |
| 638 | 643 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); |
| 639 | | try self.writeAtom(atom, &buffer, self.got_section_index.?); |
| 644 | try self.writeAtom(atom, &buffer); |
| 640 | 645 | }, |
| 641 | 646 | } |
| 642 | 647 | } |
| 643 | 648 | |
| 644 | | fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) ![]const u8 { |
| 645 | | const gpa = self.base.allocator; |
| 646 | | const resolved = try gpa.dupe(u8, code); |
| 647 | | const relocs = self.relocs.get(atom) orelse return resolved; |
| 649 | fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 650 | const relocs = self.relocs.get(atom) orelse return; |
| 651 | const source_sym = atom.getSymbol(self); |
| 652 | const source_section = self.sections.get(@enumToInt(source_sym.section_number) - 1).header; |
| 653 | const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address; |
| 654 | |
| 655 | log.debug("relocating '{s}'", .{atom.getName(self)}); |
| 648 | 656 | |
| 649 | 657 | for (relocs.items) |*reloc| { |
| 650 | | const target_sym = self.getSymbol(reloc.target); |
| 651 | | const target_vaddr = target_sym.value + reloc.addend; |
| 652 | | if (target_vaddr == reloc.prev_vaddr) continue; |
| 658 | const target_vaddr = switch (reloc.@"type") { |
| 659 | .got_pcrel => blk: { |
| 660 | const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue; |
| 661 | break :blk got_atom.getSymbol(self).value; |
| 662 | }, |
| 663 | .direct => self.getSymbol(reloc.target).value, |
| 664 | }; |
| 665 | const target_vaddr_with_addend = target_vaddr + reloc.addend; |
| 653 | 666 | |
| 654 | | log.debug(" ({x}: [() => 0x{x} ({s}))", .{ reloc.offset, target_vaddr, self.getSymbolName(reloc.target) }); |
| 667 | if (target_vaddr_with_addend == reloc.prev_vaddr) continue; |
| 655 | 668 | |
| 656 | | switch (self.ptr_width) { |
| 657 | | .p32 => mem.writeIntLittle(u32, resolved[reloc.offset..][0..4], @intCast(u32, target_vaddr)), |
| 658 | | .p64 => mem.writeIntLittle(u64, resolved[reloc.offset..][0..8], target_vaddr), |
| 669 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ |
| 670 | reloc.offset, |
| 671 | target_vaddr_with_addend, |
| 672 | self.getSymbolName(reloc.target), |
| 673 | @tagName(reloc.@"type"), |
| 674 | }); |
| 675 | |
| 676 | switch (reloc.@"type") { |
| 677 | .got_pcrel => { |
| 678 | const source_vaddr = source_sym.value + reloc.offset; |
| 679 | const disp = target_vaddr_with_addend - source_vaddr - 4; |
| 680 | try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset); |
| 681 | }, |
| 682 | .direct => switch (self.ptr_width) { |
| 683 | .p32 => try self.base.file.?.pwriteAll( |
| 684 | mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)), |
| 685 | file_offset + reloc.offset, |
| 686 | ), |
| 687 | .p64 => try self.base.file.?.pwriteAll( |
| 688 | mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)), |
| 689 | file_offset + reloc.offset, |
| 690 | ), |
| 691 | }, |
| 659 | 692 | } |
| 660 | 693 | |
| 661 | | reloc.prev_vaddr = target_vaddr; |
| 694 | reloc.prev_vaddr = target_vaddr_with_addend; |
| 662 | 695 | } |
| 663 | | |
| 664 | | return resolved; |
| 665 | 696 | } |
| 666 | 697 | |
| 667 | | fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void { |
| 698 | fn freeAtom(self: *Coff, atom: *Atom) void { |
| 668 | 699 | log.debug("freeAtom {*}", .{atom}); |
| 669 | 700 | |
| 701 | const sym = atom.getSymbol(self); |
| 702 | const sect_id = @enumToInt(sym.section_number) - 1; |
| 670 | 703 | const free_list = &self.sections.items(.free_list)[sect_id]; |
| 671 | 704 | var already_have_free_list_node = false; |
| 672 | 705 | { |
| ... | ... | @@ -858,11 +891,14 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 858 | 891 | assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 859 | 892 | if (atom.size != 0) { |
| 860 | 893 | const sym = atom.getSymbolPtr(self); |
| 894 | try self.setSymbolName(sym, decl_name); |
| 895 | sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1); |
| 896 | sym.@"type" = .{ .complex_type = complex_type, .base_type = .NULL }; |
| 897 | |
| 861 | 898 | const capacity = atom.capacity(self); |
| 862 | 899 | const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment); |
| 863 | | |
| 864 | 900 | if (need_realloc) { |
| 865 | | const vaddr = try self.growAtom(atom, code_len, required_alignment, sect_index); |
| 901 | const vaddr = try self.growAtom(atom, code_len, required_alignment); |
| 866 | 902 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr }); |
| 867 | 903 | log.debug(" (required alignment 0x{x}", .{required_alignment}); |
| 868 | 904 | |
| ... | ... | @@ -873,24 +909,20 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 873 | 909 | try self.writeGotAtom(got_atom); |
| 874 | 910 | } |
| 875 | 911 | } else if (code_len < atom.size) { |
| 876 | | self.shrinkAtom(atom, code_len, sect_index); |
| 912 | self.shrinkAtom(atom, code_len); |
| 877 | 913 | } |
| 878 | 914 | atom.size = code_len; |
| 879 | | try self.setSymbolName(sym, decl_name); |
| 880 | | sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1); |
| 881 | | sym.@"type" = .{ .complex_type = complex_type, .base_type = .NULL }; |
| 882 | 915 | } else { |
| 883 | 916 | const sym = atom.getSymbolPtr(self); |
| 884 | 917 | try self.setSymbolName(sym, decl_name); |
| 885 | | const vaddr = try self.allocateAtom(atom, code_len, required_alignment, sect_index); |
| 886 | | errdefer self.freeAtom(atom, sect_index); |
| 918 | sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1); |
| 919 | sym.@"type" = .{ .complex_type = complex_type, .base_type = .NULL }; |
| 887 | 920 | |
| 921 | const vaddr = try self.allocateAtom(atom, code_len, required_alignment); |
| 922 | errdefer self.freeAtom(atom); |
| 888 | 923 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr }); |
| 889 | | |
| 890 | 924 | atom.size = code_len; |
| 891 | 925 | sym.value = vaddr; |
| 892 | | sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1); |
| 893 | | sym.@"type" = .{ .complex_type = complex_type, .base_type = .NULL }; |
| 894 | 926 | |
| 895 | 927 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 896 | 928 | _ = try self.allocateGotEntry(got_target); |
| ... | ... | @@ -898,7 +930,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 898 | 930 | try self.writeGotAtom(got_atom); |
| 899 | 931 | } |
| 900 | 932 | |
| 901 | | try self.writeAtom(atom, code, sect_index); |
| 933 | try self.writeAtom(atom, code); |
| 902 | 934 | } |
| 903 | 935 | |
| 904 | 936 | pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| ... | ... | @@ -912,8 +944,8 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| 912 | 944 | log.debug("freeDecl {*}", .{decl}); |
| 913 | 945 | |
| 914 | 946 | const kv = self.decls.fetchRemove(decl_index); |
| 915 | | if (kv.?.value) |index| { |
| 916 | | self.freeAtom(&decl.link.coff, index); |
| 947 | if (kv.?.value) |_| { |
| 948 | self.freeAtom(&decl.link.coff); |
| 917 | 949 | } |
| 918 | 950 | |
| 919 | 951 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| ... | ... | @@ -1134,6 +1166,13 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1134 | 1166 | self.logSymtab(); |
| 1135 | 1167 | } |
| 1136 | 1168 | |
| 1169 | { |
| 1170 | var it = self.relocs.keyIterator(); |
| 1171 | while (it.next()) |atom| { |
| 1172 | try self.resolveRelocs(atom.*); |
| 1173 | } |
| 1174 | } |
| 1175 | |
| 1137 | 1176 | if (self.getEntryPoint()) |entry_sym_loc| { |
| 1138 | 1177 | self.entry_addr = self.getSymbol(entry_sym_loc).value; |
| 1139 | 1178 | } |