| ... | ... | @@ -931,6 +931,94 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 931 | 931 | } |
| 932 | 932 | } |
| 933 | 933 | |
| 934 | fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u64) !void { |
| 935 | // TODO Also detect virtual address collisions. |
| 936 | const shdr = &self.sections.items[shdr_index]; |
| 937 | const phdr = &self.program_headers.items[phdr_index]; |
| 938 | |
| 939 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 940 | // Must move the entire section. |
| 941 | const new_offset = self.findFreeSpace(needed_size, self.page_size); |
| 942 | const existing_size = if (self.atoms.get(phdr_index)) |last| blk: { |
| 943 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 944 | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; |
| 945 | } else if (shdr_index == self.got_section_index.?) blk: { |
| 946 | break :blk shdr.sh_size; |
| 947 | } else 0; |
| 948 | shdr.sh_size = 0; |
| 949 | |
| 950 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ |
| 951 | self.getString(shdr.sh_name), |
| 952 | new_offset, |
| 953 | new_offset + existing_size, |
| 954 | }); |
| 955 | |
| 956 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size); |
| 957 | if (amt != existing_size) return error.InputOutput; |
| 958 | |
| 959 | shdr.sh_offset = new_offset; |
| 960 | phdr.p_offset = new_offset; |
| 961 | } |
| 962 | |
| 963 | shdr.sh_size = needed_size; |
| 964 | phdr.p_memsz = needed_size; |
| 965 | phdr.p_filesz = needed_size; |
| 966 | |
| 967 | self.markDirty(shdr_index, phdr_index); |
| 968 | } |
| 969 | |
| 970 | pub fn growNonAllocSection(self: *Elf, shdr_index: u16, needed_size: u64, min_alignment: u32) !void { |
| 971 | const shdr = &self.sections.items[shdr_index]; |
| 972 | |
| 973 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 974 | const existing_size = if (self.symtab_section_index.? == shdr_index) blk: { |
| 975 | const sym_size: u64 = switch (self.ptr_width) { |
| 976 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 977 | .p64 => @sizeOf(elf.Elf64_Sym), |
| 978 | }; |
| 979 | break :blk @as(u64, shdr.sh_info) * sym_size; |
| 980 | } else shdr.sh_size; |
| 981 | shdr.sh_size = 0; |
| 982 | // Move all the symbols to a new file location. |
| 983 | const new_offset = self.findFreeSpace(needed_size, min_alignment); |
| 984 | log.debug("moving '{s}' from 0x{x} to 0x{x}", .{ self.getString(shdr.sh_name), shdr.sh_offset, new_offset }); |
| 985 | const amt = try self.base.file.?.copyRangeAll( |
| 986 | shdr.sh_offset, |
| 987 | self.base.file.?, |
| 988 | new_offset, |
| 989 | existing_size, |
| 990 | ); |
| 991 | if (amt != existing_size) return error.InputOutput; |
| 992 | shdr.sh_offset = new_offset; |
| 993 | } |
| 994 | |
| 995 | shdr.sh_size = needed_size; // anticipating adding the global symbols later |
| 996 | |
| 997 | self.markDirty(shdr_index, null); |
| 998 | } |
| 999 | |
| 1000 | pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void { |
| 1001 | self.shdr_table_dirty = true; // TODO look into only writing one section |
| 1002 | |
| 1003 | if (phdr_index) |_| { |
| 1004 | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty |
| 1005 | } |
| 1006 | |
| 1007 | if (self.dwarf) |_| { |
| 1008 | if (self.debug_info_section_index.? == shdr_index) { |
| 1009 | self.debug_info_header_dirty = true; |
| 1010 | } else if (self.debug_line_section_index.? == shdr_index) { |
| 1011 | self.debug_line_header_dirty = true; |
| 1012 | } else if (self.debug_abbrev_section_index.? == shdr_index) { |
| 1013 | self.debug_abbrev_section_dirty = true; |
| 1014 | } else if (self.debug_str_section_index.? == shdr_index) { |
| 1015 | self.debug_strtab_dirty = true; |
| 1016 | } else if (self.debug_aranges_section_index.? == shdr_index) { |
| 1017 | self.debug_aranges_section_dirty = true; |
| 1018 | } |
| 1019 | } |
| 1020 | } |
| 1021 | |
| 934 | 1022 | pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { |
| 935 | 1023 | if (self.base.options.emit == null) { |
| 936 | 1024 | if (build_options.have_llvm) { |
| ... | ... | @@ -2134,27 +2222,10 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2134 | 2222 | |
| 2135 | 2223 | const expand_text_section = block_placement == null or block_placement.?.next == null; |
| 2136 | 2224 | if (expand_text_section) { |
| 2137 | | const text_capacity = self.allocatedSize(shdr.sh_offset); |
| 2138 | 2225 | const needed_size = (vaddr + new_block_size) - phdr.p_vaddr; |
| 2139 | | if (needed_size > text_capacity) { |
| 2140 | | // Must move the entire section. |
| 2141 | | const new_offset = self.findFreeSpace(needed_size, self.page_size); |
| 2142 | | const text_size = if (self.atoms.get(phdr_index)) |last| blk: { |
| 2143 | | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2144 | | break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr; |
| 2145 | | } else 0; |
| 2146 | | log.debug("new PT_LOAD file offset 0x{x} to 0x{x}", .{ new_offset, new_offset + text_size }); |
| 2147 | | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, text_size); |
| 2148 | | if (amt != text_size) return error.InputOutput; |
| 2149 | | shdr.sh_offset = new_offset; |
| 2150 | | phdr.p_offset = new_offset; |
| 2151 | | } |
| 2226 | try self.growAllocSection(shdr_index, phdr_index, needed_size); |
| 2152 | 2227 | _ = try self.atoms.put(self.base.allocator, phdr_index, text_block); |
| 2153 | 2228 | |
| 2154 | | shdr.sh_size = needed_size; |
| 2155 | | phdr.p_memsz = needed_size; |
| 2156 | | phdr.p_filesz = needed_size; |
| 2157 | | |
| 2158 | 2229 | if (self.dwarf) |_| { |
| 2159 | 2230 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address |
| 2160 | 2231 | // range of the compilation unit. When we expand the text section, this range changes, |
| ... | ... | @@ -2165,9 +2236,6 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al |
| 2165 | 2236 | // model each package as a different compilation unit. |
| 2166 | 2237 | self.debug_aranges_section_dirty = true; |
| 2167 | 2238 | } |
| 2168 | | |
| 2169 | | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty |
| 2170 | | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 2171 | 2239 | } |
| 2172 | 2240 | shdr.sh_addralign = math.max(shdr.sh_addralign, alignment); |
| 2173 | 2241 | |
| ... | ... | @@ -2747,31 +2815,14 @@ fn writeSectHeader(self: *Elf, index: usize) !void { |
| 2747 | 2815 | } |
| 2748 | 2816 | |
| 2749 | 2817 | fn writeOffsetTableEntry(self: *Elf, index: usize) !void { |
| 2750 | | const shdr = &self.sections.items[self.got_section_index.?]; |
| 2751 | | const phdr = &self.program_headers.items[self.phdr_got_index.?]; |
| 2752 | 2818 | const entry_size: u16 = self.archPtrWidthBytes(); |
| 2753 | 2819 | if (self.offset_table_count_dirty) { |
| 2754 | | // TODO Also detect virtual address collisions. |
| 2755 | | const allocated_size = self.allocatedSize(shdr.sh_offset); |
| 2756 | 2820 | const needed_size = self.offset_table.items.len * entry_size; |
| 2757 | | if (needed_size > allocated_size) { |
| 2758 | | // Must move the entire got section. |
| 2759 | | const new_offset = self.findFreeSpace(needed_size, self.page_size); |
| 2760 | | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, shdr.sh_size); |
| 2761 | | if (amt != shdr.sh_size) return error.InputOutput; |
| 2762 | | shdr.sh_offset = new_offset; |
| 2763 | | phdr.p_offset = new_offset; |
| 2764 | | } |
| 2765 | | shdr.sh_size = needed_size; |
| 2766 | | phdr.p_memsz = needed_size; |
| 2767 | | phdr.p_filesz = needed_size; |
| 2768 | | |
| 2769 | | self.shdr_table_dirty = true; // TODO look into making only the one section dirty |
| 2770 | | self.phdr_table_dirty = true; // TODO look into making only the one program header dirty |
| 2771 | | |
| 2821 | try self.growAllocSection(self.got_section_index.?, self.phdr_got_index.?, needed_size); |
| 2772 | 2822 | self.offset_table_count_dirty = false; |
| 2773 | 2823 | } |
| 2774 | 2824 | const endian = self.base.options.target.cpu.arch.endian(); |
| 2825 | const shdr = &self.sections.items[self.got_section_index.?]; |
| 2775 | 2826 | const off = shdr.sh_offset + @as(u64, entry_size) * index; |
| 2776 | 2827 | switch (entry_size) { |
| 2777 | 2828 | 2 => { |
| ... | ... | @@ -2810,23 +2861,8 @@ fn writeSymbol(self: *Elf, index: usize) !void { |
| 2810 | 2861 | .p64 => @alignOf(elf.Elf64_Sym), |
| 2811 | 2862 | }; |
| 2812 | 2863 | const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; |
| 2813 | | if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { |
| 2814 | | // Move all the symbols to a new file location. |
| 2815 | | const new_offset = self.findFreeSpace(needed_size, sym_align); |
| 2816 | | log.debug("moving '.symtab' from 0x{x} to 0x{x}", .{ syms_sect.sh_offset, new_offset }); |
| 2817 | | const existing_size = @as(u64, syms_sect.sh_info) * sym_size; |
| 2818 | | const amt = try self.base.file.?.copyRangeAll( |
| 2819 | | syms_sect.sh_offset, |
| 2820 | | self.base.file.?, |
| 2821 | | new_offset, |
| 2822 | | existing_size, |
| 2823 | | ); |
| 2824 | | if (amt != existing_size) return error.InputOutput; |
| 2825 | | syms_sect.sh_offset = new_offset; |
| 2826 | | } |
| 2864 | try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align); |
| 2827 | 2865 | syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len); |
| 2828 | | syms_sect.sh_size = needed_size; // anticipating adding the global symbols later |
| 2829 | | self.shdr_table_dirty = true; // TODO look into only writing one section |
| 2830 | 2866 | } |
| 2831 | 2867 | const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); |
| 2832 | 2868 | const off = switch (self.ptr_width) { |
| ... | ... | @@ -2874,22 +2910,7 @@ fn writeAllGlobalSymbols(self: *Elf) !void { |
| 2874 | 2910 | .p64 => @alignOf(elf.Elf64_Sym), |
| 2875 | 2911 | }; |
| 2876 | 2912 | const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size; |
| 2877 | | if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { |
| 2878 | | // Move all the symbols to a new file location. |
| 2879 | | const new_offset = self.findFreeSpace(needed_size, sym_align); |
| 2880 | | log.debug("moving '.symtab' from 0x{x} to 0x{x}", .{ syms_sect.sh_offset, new_offset }); |
| 2881 | | const existing_size = @as(u64, syms_sect.sh_info) * sym_size; |
| 2882 | | const amt = try self.base.file.?.copyRangeAll( |
| 2883 | | syms_sect.sh_offset, |
| 2884 | | self.base.file.?, |
| 2885 | | new_offset, |
| 2886 | | existing_size, |
| 2887 | | ); |
| 2888 | | if (amt != existing_size) return error.InputOutput; |
| 2889 | | syms_sect.sh_offset = new_offset; |
| 2890 | | } |
| 2891 | | syms_sect.sh_size = needed_size; // anticipating adding the global symbols later |
| 2892 | | self.shdr_table_dirty = true; // TODO look into only writing one section |
| 2913 | try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align); |
| 2893 | 2914 | |
| 2894 | 2915 | const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); |
| 2895 | 2916 | const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; |