| ... | ... | @@ -8,6 +8,11 @@ const fs = std.fs; |
| 8 | 8 | const elf = std.elf; |
| 9 | 9 | const codegen = @import("codegen.zig"); |
| 10 | 10 | const c_codegen = @import("codegen/c.zig"); |
| 11 | const log = std.log; |
| 12 | const DW = std.dwarf; |
| 13 | |
| 14 | // TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented. |
| 15 | // zig fmt: off |
| 11 | 16 | |
| 12 | 17 | const default_entry_addr = 0x8000000; |
| 13 | 18 | |
| ... | ... | @@ -17,6 +22,8 @@ pub const Options = struct { |
| 17 | 22 | link_mode: std.builtin.LinkMode, |
| 18 | 23 | object_format: std.builtin.ObjectFormat, |
| 19 | 24 | optimize_mode: std.builtin.Mode, |
| 25 | root_name: []const u8, |
| 26 | root_src_dir_path: []const u8, |
| 20 | 27 | /// Used for calculating how much space to reserve for symbols in case the binary file |
| 21 | 28 | /// does not already have a symbol table. |
| 22 | 29 | symbol_count_hint: u64 = 32, |
| ... | ... | @@ -319,12 +326,18 @@ pub const File = struct { |
| 319 | 326 | phdr_got_index: ?u16 = null, |
| 320 | 327 | entry_addr: ?u64 = null, |
| 321 | 328 | |
| 329 | debug_strtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, |
| 322 | 330 | shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){}, |
| 323 | 331 | shstrtab_index: ?u16 = null, |
| 324 | 332 | |
| 325 | 333 | text_section_index: ?u16 = null, |
| 326 | 334 | symtab_section_index: ?u16 = null, |
| 327 | 335 | got_section_index: ?u16 = null, |
| 336 | debug_info_section_index: ?u16 = null, |
| 337 | debug_abbrev_section_index: ?u16 = null, |
| 338 | debug_str_section_index: ?u16 = null, |
| 339 | |
| 340 | debug_abbrev_table_offset: ?u64 = null, |
| 328 | 341 | |
| 329 | 342 | /// The same order as in the file. ELF requires global symbols to all be after the |
| 330 | 343 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and |
| ... | ... | @@ -345,7 +358,10 @@ pub const File = struct { |
| 345 | 358 | phdr_table_dirty: bool = false, |
| 346 | 359 | shdr_table_dirty: bool = false, |
| 347 | 360 | shstrtab_dirty: bool = false, |
| 361 | debug_strtab_dirty: bool = false, |
| 348 | 362 | offset_table_count_dirty: bool = false, |
| 363 | debug_info_section_dirty: bool = false, |
| 364 | debug_abbrev_section_dirty: bool = false, |
| 349 | 365 | |
| 350 | 366 | error_flags: ErrorFlags = ErrorFlags{}, |
| 351 | 367 | |
| ... | ... | @@ -434,6 +450,7 @@ pub const File = struct { |
| 434 | 450 | self.sections.deinit(self.allocator); |
| 435 | 451 | self.program_headers.deinit(self.allocator); |
| 436 | 452 | self.shstrtab.deinit(self.allocator); |
| 453 | self.debug_strtab.deinit(self.allocator); |
| 437 | 454 | self.local_symbols.deinit(self.allocator); |
| 438 | 455 | self.global_symbols.deinit(self.allocator); |
| 439 | 456 | self.global_symbol_free_list.deinit(self.allocator); |
| ... | ... | @@ -545,6 +562,14 @@ pub const File = struct { |
| 545 | 562 | return @intCast(u32, result); |
| 546 | 563 | } |
| 547 | 564 | |
| 565 | fn makeDebugString(self: *Elf, bytes: []const u8) !u32 { |
| 566 | try self.debug_strtab.ensureCapacity(self.allocator, self.debug_strtab.items.len + bytes.len + 1); |
| 567 | const result = self.debug_strtab.items.len; |
| 568 | self.debug_strtab.appendSliceAssumeCapacity(bytes); |
| 569 | self.debug_strtab.appendAssumeCapacity(0); |
| 570 | return @intCast(u32, result); |
| 571 | } |
| 572 | |
| 548 | 573 | fn getString(self: *Elf, str_off: u32) []const u8 { |
| 549 | 574 | assert(str_off < self.shstrtab.items.len); |
| 550 | 575 | return mem.spanZ(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off)); |
| ... | ... | @@ -572,7 +597,7 @@ pub const File = struct { |
| 572 | 597 | const file_size = self.base.options.program_code_size_hint; |
| 573 | 598 | const p_align = 0x1000; |
| 574 | 599 | const off = self.findFreeSpace(file_size, p_align); |
| 575 | | std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 600 | log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 576 | 601 | try self.program_headers.append(self.allocator, .{ |
| 577 | 602 | .p_type = elf.PT_LOAD, |
| 578 | 603 | .p_offset = off, |
| ... | ... | @@ -593,7 +618,7 @@ pub const File = struct { |
| 593 | 618 | // page align. |
| 594 | 619 | const p_align = 0x1000; |
| 595 | 620 | const off = self.findFreeSpace(file_size, p_align); |
| 596 | | std.log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 621 | log.debug(.link, "found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 597 | 622 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. |
| 598 | 623 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something |
| 599 | 624 | // else in virtual memory. |
| ... | ... | @@ -615,7 +640,7 @@ pub const File = struct { |
| 615 | 640 | assert(self.shstrtab.items.len == 0); |
| 616 | 641 | try self.shstrtab.append(self.allocator, 0); // need a 0 at position 0 |
| 617 | 642 | const off = self.findFreeSpace(self.shstrtab.items.len, 1); |
| 618 | | std.log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); |
| 643 | log.debug(.link, "found shstrtab free space 0x{x} to 0x{x}\n", .{ off, off + self.shstrtab.items.len }); |
| 619 | 644 | try self.sections.append(self.allocator, .{ |
| 620 | 645 | .sh_name = try self.makeString(".shstrtab"), |
| 621 | 646 | .sh_type = elf.SHT_STRTAB, |
| ... | ... | @@ -631,6 +656,27 @@ pub const File = struct { |
| 631 | 656 | self.shstrtab_dirty = true; |
| 632 | 657 | self.shdr_table_dirty = true; |
| 633 | 658 | } |
| 659 | if (self.debug_str_section_index == null) { |
| 660 | self.debug_str_section_index = @intCast(u16, self.sections.items.len); |
| 661 | assert(self.debug_strtab.items.len == 0); |
| 662 | try self.debug_strtab.append(self.allocator, 0); // need a 0 at position 0 |
| 663 | const off = self.findFreeSpace(self.debug_strtab.items.len, 1); |
| 664 | log.debug(.link, "found debug_strtab free space 0x{x} to 0x{x}\n", .{ off, off + self.debug_strtab.items.len }); |
| 665 | try self.sections.append(self.allocator, .{ |
| 666 | .sh_name = try self.makeString(".debug_str"), |
| 667 | .sh_type = elf.SHT_PROGBITS, |
| 668 | .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS, |
| 669 | .sh_addr = 0, |
| 670 | .sh_offset = off, |
| 671 | .sh_size = self.debug_strtab.items.len, |
| 672 | .sh_link = 0, |
| 673 | .sh_info = 0, |
| 674 | .sh_addralign = 1, |
| 675 | .sh_entsize = 1, |
| 676 | }); |
| 677 | self.debug_strtab_dirty = true; |
| 678 | self.shdr_table_dirty = true; |
| 679 | } |
| 634 | 680 | if (self.text_section_index == null) { |
| 635 | 681 | self.text_section_index = @intCast(u16, self.sections.items.len); |
| 636 | 682 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| ... | ... | @@ -673,7 +719,7 @@ pub const File = struct { |
| 673 | 719 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); |
| 674 | 720 | const file_size = self.base.options.symbol_count_hint * each_size; |
| 675 | 721 | const off = self.findFreeSpace(file_size, min_align); |
| 676 | | std.log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 722 | log.debug(.link, "found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 677 | 723 | |
| 678 | 724 | try self.sections.append(self.allocator, .{ |
| 679 | 725 | .sh_name = try self.makeString(".symtab"), |
| ... | ... | @@ -691,6 +737,56 @@ pub const File = struct { |
| 691 | 737 | self.shdr_table_dirty = true; |
| 692 | 738 | try self.writeSymbol(0); |
| 693 | 739 | } |
| 740 | if (self.debug_info_section_index == null) { |
| 741 | self.debug_info_section_index = @intCast(u16, self.sections.items.len); |
| 742 | |
| 743 | const file_size_hint = 200; |
| 744 | const p_align = 1; |
| 745 | const off = self.findFreeSpace(file_size_hint, p_align); |
| 746 | log.debug(.link, "found .debug_info free space 0x{x} to 0x{x}\n", .{ |
| 747 | off, |
| 748 | off + file_size_hint, |
| 749 | }); |
| 750 | try self.sections.append(self.allocator, .{ |
| 751 | .sh_name = try self.makeString(".debug_info"), |
| 752 | .sh_type = elf.SHT_PROGBITS, |
| 753 | .sh_flags = 0, |
| 754 | .sh_addr = 0, |
| 755 | .sh_offset = off, |
| 756 | .sh_size = file_size_hint, |
| 757 | .sh_link = 0, |
| 758 | .sh_info = 0, |
| 759 | .sh_addralign = p_align, |
| 760 | .sh_entsize = 0, |
| 761 | }); |
| 762 | self.shdr_table_dirty = true; |
| 763 | self.debug_info_section_dirty = true; |
| 764 | } |
| 765 | if (self.debug_abbrev_section_index == null) { |
| 766 | self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len); |
| 767 | |
| 768 | const file_size_hint = 128; |
| 769 | const p_align = 1; |
| 770 | const off = self.findFreeSpace(file_size_hint, p_align); |
| 771 | log.debug(.link, "found .debug_abbrev free space 0x{x} to 0x{x}\n", .{ |
| 772 | off, |
| 773 | off + file_size_hint, |
| 774 | }); |
| 775 | try self.sections.append(self.allocator, .{ |
| 776 | .sh_name = try self.makeString(".debug_abbrev"), |
| 777 | .sh_type = elf.SHT_PROGBITS, |
| 778 | .sh_flags = 0, |
| 779 | .sh_addr = 0, |
| 780 | .sh_offset = off, |
| 781 | .sh_size = file_size_hint, |
| 782 | .sh_link = 0, |
| 783 | .sh_info = 0, |
| 784 | .sh_addralign = p_align, |
| 785 | .sh_entsize = 0, |
| 786 | }); |
| 787 | self.shdr_table_dirty = true; |
| 788 | self.debug_abbrev_section_dirty = true; |
| 789 | } |
| 694 | 790 | const shsize: u64 = switch (self.ptr_width) { |
| 695 | 791 | .p32 => @sizeOf(elf.Elf32_Shdr), |
| 696 | 792 | .p64 => @sizeOf(elf.Elf64_Shdr), |
| ... | ... | @@ -726,12 +822,141 @@ pub const File = struct { |
| 726 | 822 | |
| 727 | 823 | /// Commit pending changes and write headers. |
| 728 | 824 | pub fn flush(self: *Elf) !void { |
| 729 | | const foreign_endian = self.base.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 825 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 826 | const foreign_endian = target_endian != std.Target.current.cpu.arch.endian(); |
| 730 | 827 | |
| 731 | 828 | // Unfortunately these have to be buffered and done at the end because ELF does not allow |
| 732 | 829 | // mixing local and global symbols within a symbol table. |
| 733 | 830 | try self.writeAllGlobalSymbols(); |
| 734 | 831 | |
| 832 | if (self.debug_abbrev_section_dirty) { |
| 833 | const debug_abbrev_sect = &self.sections.items[self.debug_abbrev_section_index.?]; |
| 834 | |
| 835 | // These are LEB encoded but since the values are all less than 127 |
| 836 | // we can simply append these bytes. |
| 837 | const abbrev_buf = [_]u8{ |
| 838 | 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header |
| 839 | //DW.AT_stmt_list, DW.FORM_data4, TODO |
| 840 | DW.AT_low_pc , DW.FORM_addr, |
| 841 | DW.AT_high_pc , DW.FORM_addr, |
| 842 | DW.AT_name , DW.FORM_strp, |
| 843 | DW.AT_comp_dir , DW.FORM_strp, |
| 844 | DW.AT_producer , DW.FORM_strp, |
| 845 | DW.AT_language , DW.FORM_data2, |
| 846 | 0, 0, // table sentinel |
| 847 | |
| 848 | 0, 0, 0, // section sentinel |
| 849 | }; |
| 850 | |
| 851 | const needed_size = abbrev_buf.len; |
| 852 | const allocated_size = self.allocatedSize(debug_abbrev_sect.sh_offset); |
| 853 | if (needed_size > allocated_size) { |
| 854 | debug_abbrev_sect.sh_size = 0; // free the space |
| 855 | debug_abbrev_sect.sh_offset = self.findFreeSpace(needed_size, 1); |
| 856 | } |
| 857 | debug_abbrev_sect.sh_size = needed_size; |
| 858 | log.debug(.link, ".debug_abbrev start=0x{x} end=0x{x}\n", .{ |
| 859 | debug_abbrev_sect.sh_offset, |
| 860 | debug_abbrev_sect.sh_offset + needed_size, |
| 861 | }); |
| 862 | |
| 863 | const abbrev_offset = 0; |
| 864 | self.debug_abbrev_table_offset = abbrev_offset; |
| 865 | try self.file.?.pwriteAll(&abbrev_buf, debug_abbrev_sect.sh_offset + abbrev_offset); |
| 866 | if (!self.shdr_table_dirty) { |
| 867 | // Then it won't get written with the others and we need to do it. |
| 868 | try self.writeSectHeader(self.debug_abbrev_section_index.?); |
| 869 | } |
| 870 | |
| 871 | self.debug_abbrev_section_dirty = false; |
| 872 | } |
| 873 | if (self.debug_info_section_dirty) { |
| 874 | const debug_info_sect = &self.sections.items[self.debug_info_section_index.?]; |
| 875 | |
| 876 | var di_buf = std.ArrayList(u8).init(self.allocator); |
| 877 | defer di_buf.deinit(); |
| 878 | |
| 879 | // Enough for a 64-bit header and main compilation unit without resizing. |
| 880 | try di_buf.ensureCapacity(100); |
| 881 | |
| 882 | // initial length - length of the .debug_info contribution for this compilation unit, |
| 883 | // not including the initial length itself. |
| 884 | // We have to come back and write it later after we know the size. |
| 885 | const init_len_index = di_buf.items.len; |
| 886 | switch (self.ptr_width) { |
| 887 | .p32 => di_buf.items.len += 4, |
| 888 | .p64 => di_buf.items.len += 12, |
| 889 | } |
| 890 | const after_init_len = di_buf.items.len; |
| 891 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), 5, target_endian); // DWARF version |
| 892 | di_buf.appendAssumeCapacity(DW.UT_compile); |
| 893 | const abbrev_offset = self.debug_abbrev_table_offset.?; |
| 894 | switch (self.ptr_width) { |
| 895 | .p32 => { |
| 896 | di_buf.appendAssumeCapacity(4); // address size |
| 897 | mem.writeInt(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, abbrev_offset), target_endian); |
| 898 | }, |
| 899 | .p64 => { |
| 900 | di_buf.appendAssumeCapacity(8); // address size |
| 901 | mem.writeInt(u64, di_buf.addManyAsArrayAssumeCapacity(8), abbrev_offset, target_endian); |
| 902 | }, |
| 903 | } |
| 904 | // Write the form for the compile unit, which must match the abbrev table above. |
| 905 | const name_strp = try self.makeDebugString(self.base.options.root_name); |
| 906 | const comp_dir_strp = try self.makeDebugString(self.base.options.root_src_dir_path); |
| 907 | const producer_strp = try self.makeDebugString("zig (TODO version here)"); |
| 908 | // Currently only one compilation unit is supported, so the address range is simply |
| 909 | // identical to the main program header virtual address and memory size. |
| 910 | const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 911 | const low_pc = text_phdr.p_vaddr; |
| 912 | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; |
| 913 | |
| 914 | di_buf.appendAssumeCapacity(1); // abbrev tag, matching the value from the abbrev table header |
| 915 | //DW.AT_stmt_list, DW.FORM_data4, TODO line information |
| 916 | self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc); |
| 917 | self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc); |
| 918 | self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp); |
| 919 | self.writeDwarfAddrAssumeCapacity(&di_buf, comp_dir_strp); |
| 920 | self.writeDwarfAddrAssumeCapacity(&di_buf, producer_strp); |
| 921 | // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: |
| 922 | // http://dwarfstd.org/ShowIssue.php?issue=171115.1 |
| 923 | // Until then we say it is C99. |
| 924 | mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian); |
| 925 | |
| 926 | const init_len = di_buf.items.len - after_init_len; |
| 927 | switch (self.ptr_width) { |
| 928 | .p32 => { |
| 929 | mem.writeInt(u32, di_buf.items[init_len_index..][0..4], @intCast(u32, init_len), target_endian); |
| 930 | }, |
| 931 | .p64 => { |
| 932 | // initial length - length of the .debug_info contribution for this compilation unit, |
| 933 | // not including the initial length itself. |
| 934 | di_buf.items[init_len_index..][0..4].* = [_]u8{ 0xff, 0xff, 0xff, 0xff }; |
| 935 | mem.writeInt(u64, di_buf.items[init_len_index + 4..][0..8], init_len, target_endian); |
| 936 | }, |
| 937 | } |
| 938 | |
| 939 | const needed_size = di_buf.items.len; |
| 940 | const allocated_size = self.allocatedSize(debug_info_sect.sh_offset); |
| 941 | if (needed_size > allocated_size) { |
| 942 | debug_info_sect.sh_size = 0; // free the space |
| 943 | debug_info_sect.sh_offset = self.findFreeSpace(needed_size, 1); |
| 944 | } |
| 945 | debug_info_sect.sh_size = needed_size; |
| 946 | log.debug(.link, ".debug_info start=0x{x} end=0x{x}\n", .{ |
| 947 | debug_info_sect.sh_offset, |
| 948 | debug_info_sect.sh_offset + needed_size, |
| 949 | }); |
| 950 | |
| 951 | try self.file.?.pwriteAll(di_buf.items, debug_info_sect.sh_offset); |
| 952 | if (!self.shdr_table_dirty) { |
| 953 | // Then it won't get written with the others and we need to do it. |
| 954 | try self.writeSectHeader(self.debug_info_section_index.?); |
| 955 | } |
| 956 | |
| 957 | self.debug_info_section_dirty = false; |
| 958 | } |
| 959 | |
| 735 | 960 | if (self.phdr_table_dirty) { |
| 736 | 961 | const phsize: u64 = switch (self.ptr_width) { |
| 737 | 962 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| ... | ... | @@ -789,7 +1014,7 @@ pub const File = struct { |
| 789 | 1014 | shstrtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); |
| 790 | 1015 | } |
| 791 | 1016 | shstrtab_sect.sh_size = needed_size; |
| 792 | | std.log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); |
| 1017 | log.debug(.link, "shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size }); |
| 793 | 1018 | |
| 794 | 1019 | try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset); |
| 795 | 1020 | if (!self.shdr_table_dirty) { |
| ... | ... | @@ -799,6 +1024,27 @@ pub const File = struct { |
| 799 | 1024 | self.shstrtab_dirty = false; |
| 800 | 1025 | } |
| 801 | 1026 | } |
| 1027 | { |
| 1028 | const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?]; |
| 1029 | if (self.debug_strtab_dirty or self.debug_strtab.items.len != debug_strtab_sect.sh_size) { |
| 1030 | const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset); |
| 1031 | const needed_size = self.debug_strtab.items.len; |
| 1032 | |
| 1033 | if (needed_size > allocated_size) { |
| 1034 | debug_strtab_sect.sh_size = 0; // free the space |
| 1035 | debug_strtab_sect.sh_offset = self.findFreeSpace(needed_size, 1); |
| 1036 | } |
| 1037 | debug_strtab_sect.sh_size = needed_size; |
| 1038 | log.debug(.link, "debug_strtab start=0x{x} end=0x{x}\n", .{ debug_strtab_sect.sh_offset, debug_strtab_sect.sh_offset + needed_size }); |
| 1039 | |
| 1040 | try self.file.?.pwriteAll(self.debug_strtab.items, debug_strtab_sect.sh_offset); |
| 1041 | if (!self.shdr_table_dirty) { |
| 1042 | // Then it won't get written with the others and we need to do it. |
| 1043 | try self.writeSectHeader(self.debug_str_section_index.?); |
| 1044 | } |
| 1045 | self.debug_strtab_dirty = false; |
| 1046 | } |
| 1047 | } |
| 802 | 1048 | if (self.shdr_table_dirty) { |
| 803 | 1049 | const shsize: u64 = switch (self.ptr_width) { |
| 804 | 1050 | .p32 => @sizeOf(elf.Elf32_Shdr), |
| ... | ... | @@ -835,7 +1081,7 @@ pub const File = struct { |
| 835 | 1081 | |
| 836 | 1082 | for (buf) |*shdr, i| { |
| 837 | 1083 | shdr.* = self.sections.items[i]; |
| 838 | | std.log.debug(.link, "writing section {}\n", .{shdr.*}); |
| 1084 | log.debug(.link, "writing section {}\n", .{shdr.*}); |
| 839 | 1085 | if (foreign_endian) { |
| 840 | 1086 | bswapAllFields(elf.Elf64_Shdr, shdr); |
| 841 | 1087 | } |
| ... | ... | @@ -846,7 +1092,7 @@ pub const File = struct { |
| 846 | 1092 | self.shdr_table_dirty = false; |
| 847 | 1093 | } |
| 848 | 1094 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 849 | | std.log.debug(.link, "no_entry_point_found = true\n", .{}); |
| 1095 | log.debug(.link, "no_entry_point_found = true\n", .{}); |
| 850 | 1096 | self.error_flags.no_entry_point_found = true; |
| 851 | 1097 | } else { |
| 852 | 1098 | self.error_flags.no_entry_point_found = false; |
| ... | ... | @@ -854,14 +1100,25 @@ pub const File = struct { |
| 854 | 1100 | } |
| 855 | 1101 | |
| 856 | 1102 | // The point of flush() is to commit changes, so nothing should be dirty after this. |
| 1103 | assert(!self.debug_info_section_dirty); |
| 1104 | assert(!self.debug_abbrev_section_dirty); |
| 857 | 1105 | assert(!self.phdr_table_dirty); |
| 858 | 1106 | assert(!self.shdr_table_dirty); |
| 859 | 1107 | assert(!self.shstrtab_dirty); |
| 1108 | assert(!self.debug_strtab_dirty); |
| 860 | 1109 | assert(!self.offset_table_count_dirty); |
| 861 | 1110 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 862 | 1111 | assert(syms_sect.sh_info == self.local_symbols.items.len); |
| 863 | 1112 | } |
| 864 | 1113 | |
| 1114 | fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void { |
| 1115 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 1116 | switch (self.ptr_width) { |
| 1117 | .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, addr), target_endian), |
| 1118 | .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian), |
| 1119 | } |
| 1120 | } |
| 1121 | |
| 865 | 1122 | fn writeElfHeader(self: *Elf) !void { |
| 866 | 1123 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; |
| 867 | 1124 | |
| ... | ... | @@ -1122,6 +1379,11 @@ pub const File = struct { |
| 1122 | 1379 | phdr.p_memsz = needed_size; |
| 1123 | 1380 | phdr.p_filesz = needed_size; |
| 1124 | 1381 | |
| 1382 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address |
| 1383 | // range of the compilation unit. When we expand the text section, this range changes, |
| 1384 | // so the .debug_info section becomes dirty. |
| 1385 | self.debug_info_section_dirty = true; |
| 1386 | |
| 1125 | 1387 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty |
| 1126 | 1388 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 1127 | 1389 | } |
| ... | ... | @@ -1160,10 +1422,10 @@ pub const File = struct { |
| 1160 | 1422 | try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len); |
| 1161 | 1423 | |
| 1162 | 1424 | if (self.local_symbol_free_list.popOrNull()) |i| { |
| 1163 | | std.log.debug(.link, "reusing symbol index {} for {}\n", .{ i, decl.name }); |
| 1425 | log.debug(.link, "reusing symbol index {} for {}\n", .{ i, decl.name }); |
| 1164 | 1426 | decl.link.local_sym_index = i; |
| 1165 | 1427 | } else { |
| 1166 | | std.log.debug(.link, "allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); |
| 1428 | log.debug(.link, "allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); |
| 1167 | 1429 | decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len); |
| 1168 | 1430 | _ = self.local_symbols.addOneAssumeCapacity(); |
| 1169 | 1431 | } |
| ... | ... | @@ -1231,11 +1493,11 @@ pub const File = struct { |
| 1231 | 1493 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); |
| 1232 | 1494 | if (need_realloc) { |
| 1233 | 1495 | const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment); |
| 1234 | | std.log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); |
| 1496 | log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr }); |
| 1235 | 1497 | if (vaddr != local_sym.st_value) { |
| 1236 | 1498 | local_sym.st_value = vaddr; |
| 1237 | 1499 | |
| 1238 | | std.log.debug(.link, " (writing new offset table entry)\n", .{}); |
| 1500 | log.debug(.link, " (writing new offset table entry)\n", .{}); |
| 1239 | 1501 | self.offset_table.items[decl.link.offset_table_index] = vaddr; |
| 1240 | 1502 | try self.writeOffsetTableEntry(decl.link.offset_table_index); |
| 1241 | 1503 | } |
| ... | ... | @@ -1253,7 +1515,7 @@ pub const File = struct { |
| 1253 | 1515 | const decl_name = mem.spanZ(decl.name); |
| 1254 | 1516 | const name_str_index = try self.makeString(decl_name); |
| 1255 | 1517 | const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment); |
| 1256 | | std.log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); |
| 1518 | log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr }); |
| 1257 | 1519 | errdefer self.freeTextBlock(&decl.link); |
| 1258 | 1520 | |
| 1259 | 1521 | local_sym.* = .{ |