| ... | ... | @@ -118,8 +118,12 @@ pub const ElfFile = struct { |
| 118 | 118 | symtab_section_index: ?u16 = null, |
| 119 | 119 | got_section_index: ?u16 = null, |
| 120 | 120 | |
| 121 | | /// The same order as in the file |
| 122 | | symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){}, |
| 121 | /// The same order as in the file. ELF requires global symbols to all be after the |
| 122 | /// local symbols, they cannot be mixed. So we must buffer all the global symbols and |
| 123 | /// write them at the end. These are only the local symbols. The length of this array |
| 124 | /// is the value used for sh_info in the .symtab section. |
| 125 | local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){}, |
| 126 | global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){}, |
| 123 | 127 | |
| 124 | 128 | /// Same order as in the file. The value is the absolute vaddr value. |
| 125 | 129 | /// If the vaddr of the executable program header changes, the entire |
| ... | ... | @@ -130,7 +134,6 @@ pub const ElfFile = struct { |
| 130 | 134 | shdr_table_dirty: bool = false, |
| 131 | 135 | shstrtab_dirty: bool = false, |
| 132 | 136 | offset_table_count_dirty: bool = false, |
| 133 | | symbol_count_dirty: bool = false, |
| 134 | 137 | |
| 135 | 138 | error_flags: ErrorFlags = ErrorFlags{}, |
| 136 | 139 | |
| ... | ... | @@ -156,14 +159,15 @@ pub const ElfFile = struct { |
| 156 | 159 | }; |
| 157 | 160 | |
| 158 | 161 | pub const Export = struct { |
| 159 | | sym_index: ?usize = null, |
| 162 | sym_index: ?u32 = null, |
| 160 | 163 | }; |
| 161 | 164 | |
| 162 | 165 | pub fn deinit(self: *ElfFile) void { |
| 163 | 166 | self.sections.deinit(self.allocator); |
| 164 | 167 | self.program_headers.deinit(self.allocator); |
| 165 | 168 | self.shstrtab.deinit(self.allocator); |
| 166 | | self.symbols.deinit(self.allocator); |
| 169 | self.local_symbols.deinit(self.allocator); |
| 170 | self.global_symbols.deinit(self.allocator); |
| 167 | 171 | self.offset_table.deinit(self.allocator); |
| 168 | 172 | if (self.owns_file_handle) |
| 169 | 173 | self.file.close(); |
| ... | ... | @@ -298,7 +302,10 @@ pub const ElfFile = struct { |
| 298 | 302 | if (self.phdr_got_index == null) { |
| 299 | 303 | self.phdr_got_index = @intCast(u16, self.program_headers.items.len); |
| 300 | 304 | const file_size = @as(u64, ptr_size) * self.options.symbol_count_hint; |
| 301 | | const off = self.findFreeSpace(file_size, ptr_size); |
| 305 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 306 | // page align. |
| 307 | const p_align = 0x1000; |
| 308 | const off = self.findFreeSpace(file_size, p_align); |
| 302 | 309 | //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 303 | 310 | // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at. |
| 304 | 311 | // we'll need to re-use that function anyway, in case the GOT grows and overlaps something |
| ... | ... | @@ -311,7 +318,7 @@ pub const ElfFile = struct { |
| 311 | 318 | .p_vaddr = default_got_addr, |
| 312 | 319 | .p_paddr = default_got_addr, |
| 313 | 320 | .p_memsz = file_size, |
| 314 | | .p_align = ptr_size, |
| 321 | .p_align = p_align, |
| 315 | 322 | .p_flags = elf.PF_R, |
| 316 | 323 | }); |
| 317 | 324 | self.phdr_table_dirty = true; |
| ... | ... | @@ -369,7 +376,7 @@ pub const ElfFile = struct { |
| 369 | 376 | .sh_link = 0, |
| 370 | 377 | .sh_info = 0, |
| 371 | 378 | .sh_addralign = phdr.p_align, |
| 372 | | .sh_entsize = ptr_size, |
| 379 | .sh_entsize = 0, |
| 373 | 380 | }); |
| 374 | 381 | self.shdr_table_dirty = true; |
| 375 | 382 | } |
| ... | ... | @@ -390,12 +397,12 @@ pub const ElfFile = struct { |
| 390 | 397 | .sh_size = file_size, |
| 391 | 398 | // The section header index of the associated string table. |
| 392 | 399 | .sh_link = self.shstrtab_index.?, |
| 393 | | .sh_info = @intCast(u32, self.symbols.items.len), |
| 400 | .sh_info = @intCast(u32, self.local_symbols.items.len), |
| 394 | 401 | .sh_addralign = min_align, |
| 395 | 402 | .sh_entsize = each_size, |
| 396 | 403 | }); |
| 397 | 404 | self.shdr_table_dirty = true; |
| 398 | | try self.writeAllSymbols(); |
| 405 | try self.writeSymbol(0); |
| 399 | 406 | } |
| 400 | 407 | const shsize: u64 = switch (self.ptr_width) { |
| 401 | 408 | .p32 => @sizeOf(elf.Elf32_Shdr), |
| ... | ... | @@ -427,6 +434,10 @@ pub const ElfFile = struct { |
| 427 | 434 | pub fn flush(self: *ElfFile) !void { |
| 428 | 435 | const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 429 | 436 | |
| 437 | // Unfortunately these have to be buffered and done at the end because ELF does not allow |
| 438 | // mixing local and global symbols within a symbol table. |
| 439 | try self.writeAllGlobalSymbols(); |
| 440 | |
| 430 | 441 | if (self.phdr_table_dirty) { |
| 431 | 442 | const phsize: u64 = switch (self.ptr_width) { |
| 432 | 443 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| ... | ... | @@ -552,8 +563,9 @@ pub const ElfFile = struct { |
| 552 | 563 | assert(!self.phdr_table_dirty); |
| 553 | 564 | assert(!self.shdr_table_dirty); |
| 554 | 565 | assert(!self.shstrtab_dirty); |
| 555 | | assert(!self.symbol_count_dirty); |
| 556 | 566 | assert(!self.offset_table_count_dirty); |
| 567 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 568 | assert(syms_sect.sh_info == self.local_symbols.items.len); |
| 557 | 569 | } |
| 558 | 570 | |
| 559 | 571 | fn writeElfHeader(self: *ElfFile) !void { |
| ... | ... | @@ -683,7 +695,7 @@ pub const ElfFile = struct { |
| 683 | 695 | size_capacity: u64, |
| 684 | 696 | }; |
| 685 | 697 | |
| 686 | | fn allocateTextBlock(self: *ElfFile, new_block_size: u64) !AllocatedBlock { |
| 698 | fn allocateTextBlock(self: *ElfFile, new_block_size: u64, alignment: u64) !AllocatedBlock { |
| 687 | 699 | const phdr = &self.program_headers.items[self.phdr_load_re_index.?]; |
| 688 | 700 | const shdr = &self.sections.items[self.text_section_index.?]; |
| 689 | 701 | |
| ... | ... | @@ -692,14 +704,15 @@ pub const ElfFile = struct { |
| 692 | 704 | // TODO instead of looping here, maintain a free list and a pointer to the end. |
| 693 | 705 | var last_start: u64 = phdr.p_vaddr; |
| 694 | 706 | var last_size: u64 = 0; |
| 695 | | for (self.symbols.items) |sym| { |
| 696 | | if (sym.st_value > last_start) { |
| 707 | for (self.local_symbols.items) |sym| { |
| 708 | if (sym.st_value + sym.st_size > last_start + last_size) { |
| 697 | 709 | last_start = sym.st_value; |
| 698 | 710 | last_size = sym.st_size; |
| 699 | 711 | } |
| 700 | 712 | } |
| 701 | 713 | const end_vaddr = last_start + (last_size * alloc_num / alloc_den); |
| 702 | | const needed_size = (end_vaddr + new_block_size) - phdr.p_vaddr; |
| 714 | const aligned_start_vaddr = mem.alignForwardGeneric(u64, end_vaddr, alignment); |
| 715 | const needed_size = (aligned_start_vaddr + new_block_size) - phdr.p_vaddr; |
| 703 | 716 | if (needed_size > text_capacity) { |
| 704 | 717 | // Must move the entire text section. |
| 705 | 718 | const new_offset = self.findFreeSpace(needed_size, 0x1000); |
| ... | ... | @@ -717,9 +730,9 @@ pub const ElfFile = struct { |
| 717 | 730 | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 718 | 731 | |
| 719 | 732 | return AllocatedBlock{ |
| 720 | | .vaddr = end_vaddr, |
| 721 | | .file_offset = shdr.sh_offset + (end_vaddr - phdr.p_vaddr), |
| 722 | | .size_capacity = text_capacity - end_vaddr, |
| 733 | .vaddr = aligned_start_vaddr, |
| 734 | .file_offset = shdr.sh_offset + (aligned_start_vaddr - phdr.p_vaddr), |
| 735 | .size_capacity = text_capacity - needed_size, |
| 723 | 736 | }; |
| 724 | 737 | } |
| 725 | 738 | |
| ... | ... | @@ -731,7 +744,7 @@ pub const ElfFile = struct { |
| 731 | 744 | // TODO look into using a hash map to speed up perf. |
| 732 | 745 | const text_capacity = self.allocatedSize(shdr.sh_offset); |
| 733 | 746 | var next_vaddr_start = phdr.p_vaddr + text_capacity; |
| 734 | | for (self.symbols.items) |elem| { |
| 747 | for (self.local_symbols.items) |elem| { |
| 735 | 748 | if (elem.st_value < sym.st_value) continue; |
| 736 | 749 | if (elem.st_value < next_vaddr_start) next_vaddr_start = elem.st_value; |
| 737 | 750 | } |
| ... | ... | @@ -748,7 +761,8 @@ pub const ElfFile = struct { |
| 748 | 761 | |
| 749 | 762 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 750 | 763 | const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) { |
| 751 | | .ok => |x| x, |
| 764 | .externally_managed => |x| x, |
| 765 | .appended => code_buffer.items, |
| 752 | 766 | .fail => |em| { |
| 753 | 767 | decl.analysis = .codegen_failure; |
| 754 | 768 | _ = try module.failed_decls.put(decl, em); |
| ... | ... | @@ -756,20 +770,23 @@ pub const ElfFile = struct { |
| 756 | 770 | }, |
| 757 | 771 | }; |
| 758 | 772 | |
| 773 | const required_alignment = typed_value.ty.abiAlignment(self.options.target); |
| 774 | |
| 759 | 775 | const file_offset = blk: { |
| 760 | | const code_size = code.len; |
| 761 | 776 | const stt_bits: u8 = switch (typed_value.ty.zigTypeTag()) { |
| 762 | 777 | .Fn => elf.STT_FUNC, |
| 763 | 778 | else => elf.STT_OBJECT, |
| 764 | 779 | }; |
| 765 | 780 | |
| 766 | 781 | if (decl.link.local_sym_index != 0) { |
| 767 | | const local_sym = &self.symbols.items[decl.link.local_sym_index]; |
| 782 | const local_sym = &self.local_symbols.items[decl.link.local_sym_index]; |
| 768 | 783 | const existing_block = self.findAllocatedTextBlock(local_sym.*); |
| 769 | | const file_offset = if (code_size > existing_block.size_capacity) fo: { |
| 770 | | const new_block = try self.allocateTextBlock(code_size); |
| 784 | const need_realloc = code.len > existing_block.size_capacity or |
| 785 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); |
| 786 | const file_offset = if (need_realloc) fo: { |
| 787 | const new_block = try self.allocateTextBlock(code.len, required_alignment); |
| 771 | 788 | local_sym.st_value = new_block.vaddr; |
| 772 | | local_sym.st_size = code_size; |
| 789 | local_sym.st_size = code.len; |
| 773 | 790 | |
| 774 | 791 | try self.writeOffsetTableEntry(decl.link.offset_table_index); |
| 775 | 792 | |
| ... | ... | @@ -781,27 +798,27 @@ pub const ElfFile = struct { |
| 781 | 798 | try self.writeSymbol(decl.link.local_sym_index); |
| 782 | 799 | break :blk file_offset; |
| 783 | 800 | } else { |
| 784 | | try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + 1); |
| 801 | try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1); |
| 785 | 802 | try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1); |
| 786 | 803 | const decl_name = mem.spanZ(decl.name); |
| 787 | 804 | const name_str_index = try self.makeString(decl_name); |
| 788 | | const new_block = try self.allocateTextBlock(code_size); |
| 789 | | const local_sym_index = self.symbols.items.len; |
| 805 | const new_block = try self.allocateTextBlock(code.len, required_alignment); |
| 806 | const local_sym_index = self.local_symbols.items.len; |
| 790 | 807 | const offset_table_index = self.offset_table.items.len; |
| 791 | 808 | |
| 792 | | self.symbols.appendAssumeCapacity(.{ |
| 809 | //std.debug.warn("add symbol for {} at vaddr 0x{x}, size {}\n", .{ decl.name, new_block.vaddr, code.len }); |
| 810 | self.local_symbols.appendAssumeCapacity(.{ |
| 793 | 811 | .st_name = name_str_index, |
| 794 | 812 | .st_info = (elf.STB_LOCAL << 4) | stt_bits, |
| 795 | 813 | .st_other = 0, |
| 796 | 814 | .st_shndx = self.text_section_index.?, |
| 797 | 815 | .st_value = new_block.vaddr, |
| 798 | | .st_size = code_size, |
| 816 | .st_size = code.len, |
| 799 | 817 | }); |
| 800 | | errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1); |
| 818 | errdefer self.local_symbols.shrink(self.allocator, self.local_symbols.items.len - 1); |
| 801 | 819 | self.offset_table.appendAssumeCapacity(new_block.vaddr); |
| 802 | 820 | errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1); |
| 803 | 821 | |
| 804 | | self.symbol_count_dirty = true; |
| 805 | 822 | self.offset_table_count_dirty = true; |
| 806 | 823 | |
| 807 | 824 | try self.writeSymbol(local_sym_index); |
| ... | ... | @@ -830,10 +847,10 @@ pub const ElfFile = struct { |
| 830 | 847 | decl: *const ir.Module.Decl, |
| 831 | 848 | exports: []const *ir.Module.Export, |
| 832 | 849 | ) !void { |
| 833 | | try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + exports.len); |
| 850 | try self.global_symbols.ensureCapacity(self.allocator, self.global_symbols.items.len + exports.len); |
| 834 | 851 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 835 | 852 | if (decl.link.local_sym_index == 0) return; |
| 836 | | const decl_sym = self.symbols.items[decl.link.local_sym_index]; |
| 853 | const decl_sym = self.local_symbols.items[decl.link.local_sym_index]; |
| 837 | 854 | |
| 838 | 855 | for (exports) |exp| { |
| 839 | 856 | if (exp.options.section) |section_name| { |
| ... | ... | @@ -866,7 +883,7 @@ pub const ElfFile = struct { |
| 866 | 883 | }; |
| 867 | 884 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); |
| 868 | 885 | if (exp.link.sym_index) |i| { |
| 869 | | const sym = &self.symbols.items[i]; |
| 886 | const sym = &self.global_symbols.items[i]; |
| 870 | 887 | sym.* = .{ |
| 871 | 888 | .st_name = try self.updateString(sym.st_name, exp.options.name), |
| 872 | 889 | .st_info = (stb_bits << 4) | stt_bits, |
| ... | ... | @@ -875,11 +892,10 @@ pub const ElfFile = struct { |
| 875 | 892 | .st_value = decl_sym.st_value, |
| 876 | 893 | .st_size = decl_sym.st_size, |
| 877 | 894 | }; |
| 878 | | try self.writeSymbol(i); |
| 879 | 895 | } else { |
| 880 | 896 | const name = try self.makeString(exp.options.name); |
| 881 | | const i = self.symbols.items.len; |
| 882 | | self.symbols.appendAssumeCapacity(.{ |
| 897 | const i = self.global_symbols.items.len; |
| 898 | self.global_symbols.appendAssumeCapacity(.{ |
| 883 | 899 | .st_name = name, |
| 884 | 900 | .st_info = (stb_bits << 4) | stt_bits, |
| 885 | 901 | .st_other = 0, |
| ... | ... | @@ -887,11 +903,9 @@ pub const ElfFile = struct { |
| 887 | 903 | .st_value = decl_sym.st_value, |
| 888 | 904 | .st_size = decl_sym.st_size, |
| 889 | 905 | }); |
| 890 | | errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1); |
| 891 | | try self.writeSymbol(i); |
| 906 | errdefer self.global_symbols.shrink(self.allocator, self.global_symbols.items.len - 1); |
| 892 | 907 | |
| 893 | | self.symbol_count_dirty = true; |
| 894 | | exp.link.sym_index = i; |
| 908 | exp.link.sym_index = @intCast(u32, i); |
| 895 | 909 | } |
| 896 | 910 | } |
| 897 | 911 | } |
| ... | ... | @@ -944,13 +958,17 @@ pub const ElfFile = struct { |
| 944 | 958 | fn writeOffsetTableEntry(self: *ElfFile, index: usize) !void { |
| 945 | 959 | const shdr = &self.sections.items[self.got_section_index.?]; |
| 946 | 960 | const phdr = &self.program_headers.items[self.phdr_got_index.?]; |
| 961 | const entry_size: u16 = switch (self.ptr_width) { |
| 962 | .p32 => 4, |
| 963 | .p64 => 8, |
| 964 | }; |
| 947 | 965 | if (self.offset_table_count_dirty) { |
| 948 | 966 | // TODO Also detect virtual address collisions. |
| 949 | 967 | const allocated_size = self.allocatedSize(shdr.sh_offset); |
| 950 | | const needed_size = self.symbols.items.len * shdr.sh_entsize; |
| 968 | const needed_size = self.local_symbols.items.len * entry_size; |
| 951 | 969 | if (needed_size > allocated_size) { |
| 952 | 970 | // Must move the entire got section. |
| 953 | | const new_offset = self.findFreeSpace(needed_size, @intCast(u16, shdr.sh_entsize)); |
| 971 | const new_offset = self.findFreeSpace(needed_size, entry_size); |
| 954 | 972 | const amt = try self.file.copyRangeAll(shdr.sh_offset, self.file, new_offset, shdr.sh_size); |
| 955 | 973 | if (amt != shdr.sh_size) return error.InputOutput; |
| 956 | 974 | shdr.sh_offset = new_offset; |
| ... | ... | @@ -965,7 +983,7 @@ pub const ElfFile = struct { |
| 965 | 983 | self.offset_table_count_dirty = false; |
| 966 | 984 | } |
| 967 | 985 | const endian = self.options.target.cpu.arch.endian(); |
| 968 | | const off = shdr.sh_offset + shdr.sh_entsize * index; |
| 986 | const off = shdr.sh_offset + @as(u64, entry_size) * index; |
| 969 | 987 | switch (self.ptr_width) { |
| 970 | 988 | .p32 => { |
| 971 | 989 | var buf: [4]u8 = undefined; |
| ... | ... | @@ -981,35 +999,42 @@ pub const ElfFile = struct { |
| 981 | 999 | } |
| 982 | 1000 | |
| 983 | 1001 | fn writeSymbol(self: *ElfFile, index: usize) !void { |
| 984 | | assert(index != 0); |
| 985 | 1002 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 986 | 1003 | // Make sure we are not pointlessly writing symbol data that will have to get relocated |
| 987 | 1004 | // due to running out of space. |
| 988 | | if (self.symbol_count_dirty) { |
| 1005 | if (self.local_symbols.items.len != syms_sect.sh_info) { |
| 989 | 1006 | const sym_size: u64 = switch (self.ptr_width) { |
| 990 | 1007 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 991 | 1008 | .p64 => @sizeOf(elf.Elf64_Sym), |
| 992 | 1009 | }; |
| 993 | | const allocated_size = self.allocatedSize(syms_sect.sh_offset); |
| 994 | | const needed_size = self.symbols.items.len * sym_size; |
| 995 | | if (needed_size > allocated_size) { |
| 996 | | return self.writeAllSymbols(); |
| 1010 | const sym_align: u16 = switch (self.ptr_width) { |
| 1011 | .p32 => @alignOf(elf.Elf32_Sym), |
| 1012 | .p64 => @alignOf(elf.Elf64_Sym), |
| 1013 | }; |
| 1014 | const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; |
| 1015 | if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { |
| 1016 | // Move all the symbols to a new file location. |
| 1017 | const new_offset = self.findFreeSpace(needed_size, sym_align); |
| 1018 | const existing_size = @as(u64, syms_sect.sh_info) * sym_size; |
| 1019 | const amt = try self.file.copyRangeAll(syms_sect.sh_offset, self.file, new_offset, existing_size); |
| 1020 | if (amt != existing_size) return error.InputOutput; |
| 1021 | syms_sect.sh_offset = new_offset; |
| 997 | 1022 | } |
| 998 | | syms_sect.sh_info = @intCast(u32, self.symbols.items.len); |
| 1023 | syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len); |
| 1024 | syms_sect.sh_size = needed_size; // anticipating adding the global symbols later |
| 999 | 1025 | self.shdr_table_dirty = true; // TODO look into only writing one section |
| 1000 | | self.symbol_count_dirty = false; |
| 1001 | 1026 | } |
| 1002 | 1027 | const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 1003 | 1028 | switch (self.ptr_width) { |
| 1004 | 1029 | .p32 => { |
| 1005 | 1030 | var sym = [1]elf.Elf32_Sym{ |
| 1006 | 1031 | .{ |
| 1007 | | .st_name = self.symbols.items[index].st_name, |
| 1008 | | .st_value = @intCast(u32, self.symbols.items[index].st_value), |
| 1009 | | .st_size = @intCast(u32, self.symbols.items[index].st_size), |
| 1010 | | .st_info = self.symbols.items[index].st_info, |
| 1011 | | .st_other = self.symbols.items[index].st_other, |
| 1012 | | .st_shndx = self.symbols.items[index].st_shndx, |
| 1032 | .st_name = self.local_symbols.items[index].st_name, |
| 1033 | .st_value = @intCast(u32, self.local_symbols.items[index].st_value), |
| 1034 | .st_size = @intCast(u32, self.local_symbols.items[index].st_size), |
| 1035 | .st_info = self.local_symbols.items[index].st_info, |
| 1036 | .st_other = self.local_symbols.items[index].st_other, |
| 1037 | .st_shndx = self.local_symbols.items[index].st_shndx, |
| 1013 | 1038 | }, |
| 1014 | 1039 | }; |
| 1015 | 1040 | if (foreign_endian) { |
| ... | ... | @@ -1019,7 +1044,7 @@ pub const ElfFile = struct { |
| 1019 | 1044 | try self.file.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); |
| 1020 | 1045 | }, |
| 1021 | 1046 | .p64 => { |
| 1022 | | var sym = [1]elf.Elf64_Sym{self.symbols.items[index]}; |
| 1047 | var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]}; |
| 1023 | 1048 | if (foreign_endian) { |
| 1024 | 1049 | bswapAllFields(elf.Elf64_Sym, &sym[0]); |
| 1025 | 1050 | } |
| ... | ... | @@ -1029,67 +1054,53 @@ pub const ElfFile = struct { |
| 1029 | 1054 | } |
| 1030 | 1055 | } |
| 1031 | 1056 | |
| 1032 | | fn writeAllSymbols(self: *ElfFile) !void { |
| 1057 | fn writeAllGlobalSymbols(self: *ElfFile) !void { |
| 1033 | 1058 | const syms_sect = &self.sections.items[self.symtab_section_index.?]; |
| 1034 | | const sym_align: u16 = switch (self.ptr_width) { |
| 1035 | | .p32 => @alignOf(elf.Elf32_Sym), |
| 1036 | | .p64 => @alignOf(elf.Elf64_Sym), |
| 1037 | | }; |
| 1038 | 1059 | const sym_size: u64 = switch (self.ptr_width) { |
| 1039 | 1060 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 1040 | 1061 | .p64 => @sizeOf(elf.Elf64_Sym), |
| 1041 | 1062 | }; |
| 1042 | | const allocated_size = self.allocatedSize(syms_sect.sh_offset); |
| 1043 | | const needed_size = self.symbols.items.len * sym_size; |
| 1044 | | if (needed_size > allocated_size) { |
| 1045 | | syms_sect.sh_size = 0; // free the space |
| 1046 | | syms_sect.sh_offset = self.findFreeSpace(needed_size, sym_align); |
| 1047 | | //std.debug.warn("moved symtab to 0x{x} to 0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size }); |
| 1048 | | } |
| 1049 | 1063 | //std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size }); |
| 1050 | | syms_sect.sh_size = needed_size; |
| 1051 | | syms_sect.sh_info = @intCast(u32, self.symbols.items.len); |
| 1052 | | self.symbol_count_dirty = false; |
| 1053 | | self.shdr_table_dirty = true; // TODO look into only writing one section |
| 1054 | 1064 | const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian(); |
| 1065 | const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; |
| 1055 | 1066 | switch (self.ptr_width) { |
| 1056 | 1067 | .p32 => { |
| 1057 | | const buf = try self.allocator.alloc(elf.Elf32_Sym, self.symbols.items.len); |
| 1068 | const buf = try self.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len); |
| 1058 | 1069 | defer self.allocator.free(buf); |
| 1059 | 1070 | |
| 1060 | 1071 | for (buf) |*sym, i| { |
| 1061 | 1072 | sym.* = .{ |
| 1062 | | .st_name = self.symbols.items[i].st_name, |
| 1063 | | .st_value = @intCast(u32, self.symbols.items[i].st_value), |
| 1064 | | .st_size = @intCast(u32, self.symbols.items[i].st_size), |
| 1065 | | .st_info = self.symbols.items[i].st_info, |
| 1066 | | .st_other = self.symbols.items[i].st_other, |
| 1067 | | .st_shndx = self.symbols.items[i].st_shndx, |
| 1073 | .st_name = self.global_symbols.items[i].st_name, |
| 1074 | .st_value = @intCast(u32, self.global_symbols.items[i].st_value), |
| 1075 | .st_size = @intCast(u32, self.global_symbols.items[i].st_size), |
| 1076 | .st_info = self.global_symbols.items[i].st_info, |
| 1077 | .st_other = self.global_symbols.items[i].st_other, |
| 1078 | .st_shndx = self.global_symbols.items[i].st_shndx, |
| 1068 | 1079 | }; |
| 1069 | 1080 | if (foreign_endian) { |
| 1070 | 1081 | bswapAllFields(elf.Elf32_Sym, sym); |
| 1071 | 1082 | } |
| 1072 | 1083 | } |
| 1073 | | try self.file.pwriteAll(mem.sliceAsBytes(buf), syms_sect.sh_offset); |
| 1084 | try self.file.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); |
| 1074 | 1085 | }, |
| 1075 | 1086 | .p64 => { |
| 1076 | | const buf = try self.allocator.alloc(elf.Elf64_Sym, self.symbols.items.len); |
| 1087 | const buf = try self.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len); |
| 1077 | 1088 | defer self.allocator.free(buf); |
| 1078 | 1089 | |
| 1079 | 1090 | for (buf) |*sym, i| { |
| 1080 | 1091 | sym.* = .{ |
| 1081 | | .st_name = self.symbols.items[i].st_name, |
| 1082 | | .st_value = self.symbols.items[i].st_value, |
| 1083 | | .st_size = self.symbols.items[i].st_size, |
| 1084 | | .st_info = self.symbols.items[i].st_info, |
| 1085 | | .st_other = self.symbols.items[i].st_other, |
| 1086 | | .st_shndx = self.symbols.items[i].st_shndx, |
| 1092 | .st_name = self.global_symbols.items[i].st_name, |
| 1093 | .st_value = self.global_symbols.items[i].st_value, |
| 1094 | .st_size = self.global_symbols.items[i].st_size, |
| 1095 | .st_info = self.global_symbols.items[i].st_info, |
| 1096 | .st_other = self.global_symbols.items[i].st_other, |
| 1097 | .st_shndx = self.global_symbols.items[i].st_shndx, |
| 1087 | 1098 | }; |
| 1088 | 1099 | if (foreign_endian) { |
| 1089 | 1100 | bswapAllFields(elf.Elf64_Sym, sym); |
| 1090 | 1101 | } |
| 1091 | 1102 | } |
| 1092 | | try self.file.pwriteAll(mem.sliceAsBytes(buf), syms_sect.sh_offset); |
| 1103 | try self.file.pwriteAll(mem.sliceAsBytes(buf), global_syms_off); |
| 1093 | 1104 | }, |
| 1094 | 1105 | } |
| 1095 | 1106 | } |
| ... | ... | @@ -1126,7 +1137,7 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !El |
| 1126 | 1137 | errdefer self.deinit(); |
| 1127 | 1138 | |
| 1128 | 1139 | // Index 0 is always a null symbol. |
| 1129 | | try self.symbols.append(allocator, .{ |
| 1140 | try self.local_symbols.append(allocator, .{ |
| 1130 | 1141 | .st_name = 0, |
| 1131 | 1142 | .st_info = 0, |
| 1132 | 1143 | .st_other = 0, |