| ... | @@ -104,6 +104,10 @@ unnamed_const_atoms: UnnamedConstTable = .{}, | ... | @@ -104,6 +104,10 @@ unnamed_const_atoms: UnnamedConstTable = .{}, |
| 104 | relocs: RelocTable = .{}, | 104 | relocs: RelocTable = .{}, |
| 105 | | 105 | |
| 106 | const Reloc = struct { | 106 | const Reloc = struct { |
| | 107 | @"type": enum { |
| | 108 | got_pcrel, |
| | 109 | direct, |
| | 110 | }, |
| 107 | target: SymbolWithLoc, | 111 | target: SymbolWithLoc, |
| 108 | offset: u32, | 112 | offset: u32, |
| 109 | addend: u32, | 113 | addend: u32, |
| ... | @@ -413,10 +417,11 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { | ... | @@ -413,10 +417,11 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void { |
| 413 | try self.decls.putNoClobber(gpa, decl_index, null); | 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 | const tracy = trace(@src()); | 421 | const tracy = trace(@src()); |
| 418 | defer tracy.end(); | 422 | defer tracy.end(); |
| 419 | | 423 | |
| | 424 | const sect_id = @enumToInt(atom.getSymbol(self).section_number) - 1; |
| 420 | const header = &self.sections.items(.header)[sect_id]; | 425 | const header = &self.sections.items(.header)[sect_id]; |
| 421 | const free_list = &self.sections.items(.free_list)[sect_id]; | 426 | const free_list = &self.sections.items(.free_list)[sect_id]; |
| 422 | const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; | 427 | const maybe_last_atom = &self.sections.items(.last_atom)[sect_id]; |
| ... | @@ -580,18 +585,20 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { | ... | @@ -580,18 +585,20 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 580 | | 585 | |
| 581 | try self.managed_atoms.append(gpa, atom); | 586 | try self.managed_atoms.append(gpa, atom); |
| 582 | try self.atom_by_index_table.putNoClobber(gpa, atom.sym_index, atom); | 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 | const sym = atom.getSymbolPtr(self); | 590 | const sym = atom.getSymbolPtr(self); |
| 585 | sym.value = try self.allocateAtom(atom, atom.size, atom.alignment, self.got_section_index.?); | | |
| 586 | sym.section_number = @intToEnum(coff.SectionNumber, self.got_section_index.? + 1); | 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 | const gop_relocs = try self.relocs.getOrPut(gpa, atom); | 596 | const gop_relocs = try self.relocs.getOrPut(gpa, atom); |
| 591 | if (!gop_relocs.found_existing) { | 597 | if (!gop_relocs.found_existing) { |
| 592 | gop_relocs.value_ptr.* = .{}; | 598 | gop_relocs.value_ptr.* = .{}; |
| 593 | } | 599 | } |
| 594 | try gop_relocs.value_ptr.append(gpa, .{ | 600 | try gop_relocs.value_ptr.append(gpa, .{ |
| | 601 | .@"type" = .direct, |
| 595 | .target = target, | 602 | .target = target, |
| 596 | .offset = 0, | 603 | .offset = 0, |
| 597 | .addend = 0, | 604 | .addend = 0, |
| ... | @@ -601,72 +608,98 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { | ... | @@ -601,72 +608,98 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 601 | return atom; | 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 | const sym = atom.getSymbol(self); | 612 | const sym = atom.getSymbol(self); |
| 606 | const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value; | 613 | const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value; |
| 607 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); | 614 | const need_realloc = !align_ok or new_atom_size > atom.capacity(self); |
| 608 | if (!need_realloc) return sym.value; | 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 | _ = self; | 620 | _ = self; |
| 614 | _ = atom; | 621 | _ = atom; |
| 615 | _ = new_block_size; | 622 | _ = new_block_size; |
| 616 | _ = sect_id; | | |
| 617 | // TODO check the new capacity, and if it crosses the size threshold into a big enough | 623 | // TODO check the new capacity, and if it crosses the size threshold into a big enough |
| 618 | // capacity, insert a free list node for it. | 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 { | 627 | fn writeAtom(self: *Coff, atom: *Atom, code: []const u8) !void { |
| 622 | const section = self.sections.get(sect_id); | | |
| 623 | const sym = atom.getSymbol(self); | 628 | const sym = atom.getSymbol(self); |
| | 629 | const section = self.sections.get(@enumToInt(sym.section_number) - 1); |
| 624 | const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address; | 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 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); | 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 | fn writeGotAtom(self: *Coff, atom: *Atom) !void { | 636 | fn writeGotAtom(self: *Coff, atom: *Atom) !void { |
| 632 | switch (self.ptr_width) { | 637 | switch (self.ptr_width) { |
| 633 | .p32 => { | 638 | .p32 => { |
| 634 | var buffer: [@sizeOf(u32)]u8 = [_]u8{0} ** @sizeOf(u32); | 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 | .p64 => { | 642 | .p64 => { |
| 638 | var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64); | 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 { | 649 | fn resolveRelocs(self: *Coff, atom: *Atom) !void { |
| 645 | const gpa = self.base.allocator; | 650 | const relocs = self.relocs.get(atom) orelse return; |
| 646 | const resolved = try gpa.dupe(u8, code); | 651 | const source_sym = atom.getSymbol(self); |
| 647 | const relocs = self.relocs.get(atom) orelse return resolved; | 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 | for (relocs.items) |*reloc| { | 657 | for (relocs.items) |*reloc| { |
| 650 | const target_sym = self.getSymbol(reloc.target); | 658 | const target_vaddr = switch (reloc.@"type") { |
| 651 | const target_vaddr = target_sym.value + reloc.addend; | 659 | .got_pcrel => blk: { |
| 652 | if (target_vaddr == reloc.prev_vaddr) continue; | 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) { | 669 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ |
| 657 | .p32 => mem.writeIntLittle(u32, resolved[reloc.offset..][0..4], @intCast(u32, target_vaddr)), | 670 | reloc.offset, |
| 658 | .p64 => mem.writeIntLittle(u64, resolved[reloc.offset..][0..8], target_vaddr), | 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 | log.debug("freeAtom {*}", .{atom}); | 699 | log.debug("freeAtom {*}", .{atom}); |
| 669 | | 700 | |
| | 701 | const sym = atom.getSymbol(self); |
| | 702 | const sect_id = @enumToInt(sym.section_number) - 1; |
| 670 | const free_list = &self.sections.items(.free_list)[sect_id]; | 703 | const free_list = &self.sections.items(.free_list)[sect_id]; |
| 671 | var already_have_free_list_node = false; | 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,11 +891,14 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 858 | assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes() | 891 | assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 859 | if (atom.size != 0) { | 892 | if (atom.size != 0) { |
| 860 | const sym = atom.getSymbolPtr(self); | 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 | const capacity = atom.capacity(self); | 898 | const capacity = atom.capacity(self); |
| 862 | const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment); | 899 | const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment); |
| 863 | | | |
| 864 | if (need_realloc) { | 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 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr }); | 902 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr }); |
| 867 | log.debug(" (required alignment 0x{x}", .{required_alignment}); | 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,24 +909,20 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 873 | try self.writeGotAtom(got_atom); | 909 | try self.writeGotAtom(got_atom); |
| 874 | } | 910 | } |
| 875 | } else if (code_len < atom.size) { | 911 | } else if (code_len < atom.size) { |
| 876 | self.shrinkAtom(atom, code_len, sect_index); | 912 | self.shrinkAtom(atom, code_len); |
| 877 | } | 913 | } |
| 878 | atom.size = code_len; | 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 | } else { | 915 | } else { |
| 883 | const sym = atom.getSymbolPtr(self); | 916 | const sym = atom.getSymbolPtr(self); |
| 884 | try self.setSymbolName(sym, decl_name); | 917 | try self.setSymbolName(sym, decl_name); |
| 885 | const vaddr = try self.allocateAtom(atom, code_len, required_alignment, sect_index); | 918 | sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1); |
| 886 | errdefer self.freeAtom(atom, sect_index); | 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 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr }); | 923 | log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr }); |
| 889 | | | |
| 890 | atom.size = code_len; | 924 | atom.size = code_len; |
| 891 | sym.value = vaddr; | 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 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; | 927 | const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null }; |
| 896 | _ = try self.allocateGotEntry(got_target); | 928 | _ = try self.allocateGotEntry(got_target); |
| ... | @@ -898,7 +930,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, | ... | @@ -898,7 +930,7 @@ fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, |
| 898 | try self.writeGotAtom(got_atom); | 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 | pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { | 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,8 +944,8 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| 912 | log.debug("freeDecl {*}", .{decl}); | 944 | log.debug("freeDecl {*}", .{decl}); |
| 913 | | 945 | |
| 914 | const kv = self.decls.fetchRemove(decl_index); | 946 | const kv = self.decls.fetchRemove(decl_index); |
| 915 | if (kv.?.value) |index| { | 947 | if (kv.?.value) |_| { |
| 916 | self.freeAtom(&decl.link.coff, index); | 948 | self.freeAtom(&decl.link.coff); |
| 917 | } | 949 | } |
| 918 | | 950 | |
| 919 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 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,6 +1166,13 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1134 | self.logSymtab(); | 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 | if (self.getEntryPoint()) |entry_sym_loc| { | 1176 | if (self.getEntryPoint()) |entry_sym_loc| { |
| 1138 | self.entry_addr = self.getSymbol(entry_sym_loc).value; | 1177 | self.entry_addr = self.getSymbol(entry_sym_loc).value; |
| 1139 | } | 1178 | } |