| ... | ... | @@ -49,6 +49,20 @@ globals: struct { |
| 49 | 49 | strong_undef: std.array_hash_map.Auto(String(.strtab), Symbol.Global), |
| 50 | 50 | weak_undef: std.array_hash_map.Auto(String(.strtab), Symbol.Global), |
| 51 | 51 | }, |
| 52 | /// Key is the name of an undef global for which we have created a "copy relocation" (`R_*_COPY`). |
| 53 | copied_globals: std.array_hash_map.Auto(String(.strtab), struct { |
| 54 | node: MappedFile.Node.Index, |
| 55 | /// The index of this global's runtime relocation in `.rela.dyn`. |
| 56 | rela_index: Section.RelaIndex, |
| 57 | }), |
| 58 | /// Key is the name of an undef global for which we would *like* to create a copy relocation |
| 59 | /// (`R_*_COPY`), but cannot because we have not seen an appropriate definition in a linked DSO yet. |
| 60 | /// |
| 61 | /// Therefore, if, when scanning a DSO input, we discover a definition for one of these symbols, we |
| 62 | /// will remove it from this map and call ` |
| 63 | /// |
| 64 | /// which have not created |
| 65 | want_copied_globals: std.array_hash_map.Auto(String(.strtab), void), |
| 52 | 66 | /// Key is a node which is a valid `Symbol.node` value, value is the name of the first global symbol |
| 53 | 67 | /// in that node. That symbol is the head of a linked list: see `Symbol.Global.next_in_node`. |
| 54 | 68 | /// |
| ... | ... | @@ -57,14 +71,29 @@ globals: struct { |
| 57 | 71 | /// We use a separate hash map for this data rather than storing it in `navs` etc to save memory, |
| 58 | 72 | /// because the vast majority of nodes which can export global symbols actually will not. |
| 59 | 73 | node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, String(.strtab)), |
| 60 | | /// Contains all globals symbols defined in any needed DSO. This map serves two purposes: |
| 74 | /// Contains all globals symbols defined in any needed DSO. This map serves three purposes: |
| 75 | /// |
| 76 | /// * If we discover an undefined reference to one of these symbols, we know whether the symbol has |
| 77 | /// type `STT_FUNC`, in which case we will create a PLT entry. |
| 61 | 78 | /// |
| 62 | | /// * If we discover an undefined reference to one of these symbols, we will know the associated |
| 63 | | /// symbol type, which is important because it may cause us to create a PLT entry. |
| 79 | /// * If we discover a direct relocation (i.e. no GOT or PLT indirection) targeting one of these |
| 80 | /// symbols, we know whether the symbol has type `STT_OBJECT` and we know its size and alignment, |
| 81 | /// so we can emit a copy relocation for that symbol instead of using a text relocation. |
| 64 | 82 | /// |
| 65 | 83 | /// * When emitting a dynamic executable, we can detect which undefined references are resolved by a |
| 66 | 84 | /// linked DSO, so can emit "undefined global symbol" errors for any other undefined references. |
| 67 | | dso_globals: std.array_hash_map.Auto(String(.strtab), std.elf.STT), |
| 85 | dso_globals: std.array_hash_map.Auto(String(.strtab), struct { |
| 86 | type: std.elf.STT, |
| 87 | size: u64, |
| 88 | /// This is usually unnecessary, but if a symbol is given a copy relocation (`R_*_COPY`) and so |
| 89 | /// becomes a part of the executable's address space despite being defined by a different DSO, |
| 90 | /// we need to know its alignment requirement so that we don't break other code. This isn't |
| 91 | /// actually stored on the symbol---instead we compute a maximum alignment from the alignment of |
| 92 | /// the section containing the symbol, and the symbol's offset within the section. I know this |
| 93 | /// sounds like a terrible hack, but it is *genuinely* how you're supposed to do this. Copy |
| 94 | /// relocations suck. |
| 95 | alignment: std.mem.Alignment, |
| 96 | }), |
| 68 | 97 | shstrtab: StringTable, |
| 69 | 98 | strtab: StringTable, |
| 70 | 99 | dynstr: StringTable, |
| ... | ... | @@ -136,22 +165,24 @@ synth_prog_node: std.Progress.Node, |
| 136 | 165 | input_prog_node: std.Progress.Node, |
| 137 | 166 | |
| 138 | 167 | const Node = union(enum) { |
| 139 | | /// Cannot contain relocations. |
| 140 | 168 | file, |
| 141 | | /// Cannot contain relocations. |
| 142 | 169 | ehdr, |
| 143 | | /// Cannot contain relocations. |
| 144 | 170 | shdr, |
| 145 | | /// Cannot contain relocations. |
| 146 | 171 | segment: u32, |
| 147 | 172 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. |
| 148 | 173 | /// |
| 149 | 174 | /// The section '.dynamic' may contain relocations via `elf.dynamic_first_symbol_reloc`. |
| 150 | | /// |
| 151 | | /// Otherwise, cannot contain relocations. |
| 152 | 175 | section: Section.Index, |
| 153 | 176 | /// May contain relocations. |
| 154 | 177 | input_section: InputSection.Index, |
| 178 | /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for |
| 179 | /// which we have emitted a copy relocation. |
| 180 | /// |
| 181 | /// TODO it would be better to emit these into `.bss` or `.bss.rel.ro`, once we support those. |
| 182 | /// |
| 183 | /// TODO: currently, the `elf.copied_globals` entry may not be there---this case exists because |
| 184 | /// `MappedFile` does not (yet?) support deleting nodes. See logic in `setGlobalSymbolValue`. |
| 185 | copied_global: String(.strtab), |
| 155 | 186 | /// May contain relocations. |
| 156 | 187 | nav: NavMapIndex, |
| 157 | 188 | /// May contain relocations. |
| ... | ... | @@ -746,6 +777,7 @@ const GotReloc = struct { |
| 746 | 777 | .ehdr => unreachable, |
| 747 | 778 | .shdr => unreachable, |
| 748 | 779 | .segment => unreachable, |
| 780 | .copied_global => unreachable, |
| 749 | 781 | .section => |shndx| shndx.vaddr(elf), |
| 750 | 782 | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 751 | 783 | inline .nav, |
| ... | ... | @@ -808,6 +840,15 @@ pub const MachineRelocType = union { |
| 808 | 840 | .X86_64 => .{ .X86_64 = .NONE }, |
| 809 | 841 | }; |
| 810 | 842 | } |
| 843 | pub fn copy(elf: *Elf) MachineRelocType { |
| 844 | return switch (elf.ehdrField(.machine)) { |
| 845 | else => unreachable, |
| 846 | .AARCH64 => .{ .AARCH64 = .COPY }, |
| 847 | .PPC64 => .{ .PPC64 = .COPY }, |
| 848 | .RISCV => .{ .RISCV = .COPY }, |
| 849 | .X86_64 => .{ .X86_64 = .COPY }, |
| 850 | }; |
| 851 | } |
| 811 | 852 | pub fn jumpSlot(elf: *Elf) MachineRelocType { |
| 812 | 853 | return switch (elf.ehdrField(.machine)) { |
| 813 | 854 | else => unreachable, |
| ... | ... | @@ -973,6 +1014,7 @@ const SymbolReloc = struct { |
| 973 | 1014 | .ehdr => unreachable, |
| 974 | 1015 | .shdr => unreachable, |
| 975 | 1016 | .segment => unreachable, |
| 1017 | .copied_global => unreachable, |
| 976 | 1018 | .section => |shndx| shndx.vaddr(elf), |
| 977 | 1019 | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 978 | 1020 | inline .nav, |
| ... | ... | @@ -984,11 +1026,9 @@ const SymbolReloc = struct { |
| 984 | 1026 | const dest_vaddr = node_vaddr + reloc.offset; |
| 985 | 1027 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| 986 | 1028 | const target_endian = elf.targetEndian(); |
| 987 | | const sym_value: u64, const sym_size: u64 = switch (elf.symPtr(reloc.target.index(elf))) { |
| 988 | | inline else => |target_sym| .{ |
| 989 | | elf.targetLoad(&target_sym.value), |
| 990 | | elf.targetLoad(&target_sym.size), |
| 991 | | }, |
| 1029 | const sym_value: u64 = reloc.target.value(elf); |
| 1030 | const sym_size: u64 = switch (elf.symPtr(reloc.target.index(elf))) { |
| 1031 | inline else => |target_sym| elf.targetLoad(&target_sym.size), |
| 992 | 1032 | }; |
| 993 | 1033 | const target_value = sym_value +% @as(u64, @bitCast(reloc.addend)); |
| 994 | 1034 | type: switch (reloc.type) { |
| ... | ... | @@ -1114,6 +1154,12 @@ const SymbolReloc = struct { |
| 1114 | 1154 | |
| 1115 | 1155 | fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void { |
| 1116 | 1156 | assert(index.get(elf) == reloc); |
| 1157 | |
| 1158 | reloc.deleteOutputRel(elf); |
| 1159 | if (reloc.type.dependsOnTlsSize()) { |
| 1160 | assert(elf.tls_size_symbol_relocs.swapRemove(index)); |
| 1161 | } |
| 1162 | |
| 1117 | 1163 | switch (reloc.prev) { |
| 1118 | 1164 | .none => { |
| 1119 | 1165 | const target_ptr = reloc.target.index(elf).ptr(elf); |
| ... | ... | @@ -1126,18 +1172,25 @@ const SymbolReloc = struct { |
| 1126 | 1172 | .none => {}, |
| 1127 | 1173 | else => |next| next.get(elf).prev = reloc.prev, |
| 1128 | 1174 | } |
| 1129 | | if (reloc.rela_index.unwrap()) |rela_index| { |
| 1130 | | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); |
| 1131 | | switch (elf.nodeWantsDsoRelocation(reloc.node)) { |
| 1175 | |
| 1176 | reloc.* = undefined; |
| 1177 | } |
| 1178 | |
| 1179 | /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating |
| 1180 | /// `elf.textrel_count` if necessary. |
| 1181 | fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void { |
| 1182 | const rela_index = reloc.rela_index.unwrap() orelse return; |
| 1183 | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); |
| 1184 | switch (elf.ehdrField(.type)) { |
| 1185 | .NONE, .CORE, _ => unreachable, |
| 1186 | .REL => {}, |
| 1187 | .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node)) { |
| 1132 | 1188 | .no => unreachable, // there *was* a dynamic relocation! |
| 1133 | 1189 | .yes => {}, |
| 1134 | 1190 | .yes_textrel => elf.textrel_count -= 1, |
| 1135 | | } |
| 1136 | | } |
| 1137 | | if (reloc.type.dependsOnTlsSize()) { |
| 1138 | | assert(elf.tls_size_symbol_relocs.swapRemove(index)); |
| 1191 | }, |
| 1139 | 1192 | } |
| 1140 | | reloc.* = undefined; |
| 1193 | reloc.rela_index = .none; |
| 1141 | 1194 | } |
| 1142 | 1195 | }; |
| 1143 | 1196 | |
| ... | ... | @@ -1468,7 +1521,9 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{ |
| 1468 | 1521 | }; |
| 1469 | 1522 | |
| 1470 | 1523 | const @"type": std.elf.STT = switch (opts.type) { |
| 1471 | | .NOTYPE => elf.dso_globals.get(opts.name.strtab) orelse .NOTYPE, |
| 1524 | .NOTYPE => if (elf.dso_globals.get(opts.name.strtab)) |dso_global| t: { |
| 1525 | break :t dso_global.type; |
| 1526 | } else .NOTYPE, |
| 1472 | 1527 | else => |t| t, |
| 1473 | 1528 | }; |
| 1474 | 1529 | |
| ... | ... | @@ -1605,6 +1660,23 @@ fn setGlobalSymbolValue( |
| 1605 | 1660 | assert(global_ptr.prev_in_node == .empty); |
| 1606 | 1661 | } |
| 1607 | 1662 | |
| 1663 | if (elf.copied_globals.fetchSwapRemove(global_name)) |copied_global_kv| { |
| 1664 | // This is a quite rare case: there was a definition for this symbol in a shared library |
| 1665 | // input, and we ended up emitting a copy relocation for it, but we've now got our *own* |
| 1666 | // definition which replaces it. We know that our definition cannot be preempted because we |
| 1667 | // are the executable (only executables can have copy relocations!), so we definitely do not |
| 1668 | // need the copy relocation. |
| 1669 | |
| 1670 | // All we actually need to do is remove the entry from `copied_globals` (already done), and |
| 1671 | // delete the actual `R_*_COPY` relocation. Of course, we also need to re-apply relocations |
| 1672 | // targeting this symbol, but we were going to do that at the end of this function anyway. |
| 1673 | elf.shndx.rela_dyn.relaDeleteOne(elf, copied_global_kv.value.rela_index); |
| 1674 | // TODO: once `MappedFile` has a way to delete a node (so it can re-use the space), we |
| 1675 | // should delete `copied_global_kv.value.node`, which is an "orphaned" `copied_global` node. |
| 1676 | } else { |
| 1677 | _ = elf.want_copied_globals.swapRemove(global_name); |
| 1678 | } |
| 1679 | |
| 1608 | 1680 | global_ptr.symtab_index.ptr(elf).node = new.node; |
| 1609 | 1681 | |
| 1610 | 1682 | const old_head: String(.strtab) = old_head: { |
| ... | ... | @@ -1668,21 +1740,7 @@ fn setGlobalSymbolValue( |
| 1668 | 1740 | // If this symbol was previously undefined, relocations targeting it may have been lowered to |
| 1669 | 1741 | // runtime relocations which we have now discovered we do not need, so delete those. |
| 1670 | 1742 | if (elf.shndx.dynamic != .UNDEF) { |
| 1671 | | var ri = global_ptr.symtab_index.ptr(elf).first_target_reloc; |
| 1672 | | while (ri != .none) { |
| 1673 | | const reloc = ri.get(elf); |
| 1674 | | assert(reloc.target == Symbol.Id.global(global_name)); |
| 1675 | | if (reloc.rela_index.unwrap()) |rela_index| { |
| 1676 | | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); |
| 1677 | | switch (elf.nodeWantsDsoRelocation(reloc.node)) { |
| 1678 | | .no => unreachable, // there *was* a dynamic relocation! |
| 1679 | | .yes => {}, |
| 1680 | | .yes_textrel => elf.textrel_count -= 1, |
| 1681 | | } |
| 1682 | | reloc.rela_index = .none; |
| 1683 | | } |
| 1684 | | ri = reloc.next; |
| 1685 | | } |
| 1743 | Symbol.Id.global(global_name).deleteDynamicTargetRelocs(elf); |
| 1686 | 1744 | } |
| 1687 | 1745 | |
| 1688 | 1746 | // Finally, update the symbol value, re-applying target relocations. Also note that because we |
| ... | ... | @@ -2029,6 +2087,9 @@ const Symbol = struct { |
| 2029 | 2087 | }; |
| 2030 | 2088 | } |
| 2031 | 2089 | |
| 2090 | /// Returns the value of this symbol, or 0 if it is undefined. If the symbol is an undefined |
| 2091 | /// global for which we have emitted a copy relocation, returns the virtual address of that |
| 2092 | /// copy relocation, which the symbol is guaranteed to resolve to at runtime. |
| 2032 | 2093 | fn value(s: Symbol.Id, elf: *Elf) u64 { |
| 2033 | 2094 | return switch (elf.symPtr(s.index(elf))) { |
| 2034 | 2095 | inline else => |sym| elf.targetLoad(&sym.value), |
| ... | ... | @@ -2084,12 +2145,36 @@ const Symbol = struct { |
| 2084 | 2145 | } |
| 2085 | 2146 | } |
| 2086 | 2147 | |
| 2148 | /// Scans through all relocations targeting `sym_id` and deletes each one's dynamic |
| 2149 | /// relocation entry, if it has one. |
| 2150 | /// |
| 2151 | /// Asserts we are creating a DSO. |
| 2152 | fn deleteDynamicTargetRelocs(sym_id: Symbol.Id, elf: *Elf) void { |
| 2153 | assert(elf.ehdrField(.type) != .REL); |
| 2154 | assert(elf.shndx.dynamic != .UNDEF); |
| 2155 | var ri = sym_id.index(elf).ptr(elf).first_target_reloc; |
| 2156 | while (ri != .none) { |
| 2157 | const reloc = ri.get(elf); |
| 2158 | assert(reloc.target == sym_id); |
| 2159 | reloc.deleteOutputRel(elf); |
| 2160 | ri = reloc.next; |
| 2161 | } |
| 2162 | } |
| 2163 | |
| 2087 | 2164 | /// Returns `true` if the target of `s` has moved, meaning the symbol's value will change at |
| 2088 | 2165 | /// some point due to a call to `flushMoved`. |
| 2089 | 2166 | fn hasMoved(s: Symbol.Id, elf: *Elf) bool { |
| 2090 | 2167 | const node = s.index(elf).ptr(elf).node; |
| 2091 | | if (node == .none) return false; |
| 2092 | | return node.hasMoved(&elf.mf); |
| 2168 | if (node != .none) { |
| 2169 | return node.hasMoved(&elf.mf); |
| 2170 | } |
| 2171 | switch (s.unwrap()) { |
| 2172 | .local => {}, |
| 2173 | .global => |name| if (elf.copied_globals.getPtr(name)) |copied_global| { |
| 2174 | return copied_global.node.hasMoved(&elf.mf); |
| 2175 | }, |
| 2176 | } |
| 2177 | return false; |
| 2093 | 2178 | } |
| 2094 | 2179 | }; |
| 2095 | 2180 | }; |
| ... | ... | @@ -2110,6 +2195,7 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { |
| 2110 | 2195 | .segment, |
| 2111 | 2196 | .section, |
| 2112 | 2197 | .input_section, |
| 2198 | .copied_global, |
| 2113 | 2199 | => unreachable, |
| 2114 | 2200 | |
| 2115 | 2201 | inline .nav, |
| ... | ... | @@ -2204,7 +2290,7 @@ pub fn addReloc( |
| 2204 | 2290 | ) !void { |
| 2205 | 2291 | const node: MappedFile.Node.Index = Node.fromAtom(atom); |
| 2206 | 2292 | try elf.ensureUnusedRelocCapacity(node, 1); |
| 2207 | | elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type"); |
| 2293 | try elf.addRelocAssumeCapacity(node, offset, .fromTypeErased(target), addend, @"type"); |
| 2208 | 2294 | } |
| 2209 | 2295 | pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) !link.File.SymbolId { |
| 2210 | 2296 | const zcu = elf.base.comp.zcu.?; |
| ... | ... | @@ -2252,7 +2338,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target: link.File.Sy |
| 2252 | 2338 | const node: MappedFile.Node.Index = Node.fromAtom(reloc_info.parent.atom_index); |
| 2253 | 2339 | const target_sym: Symbol.Id = .fromTypeErased(target); |
| 2254 | 2340 | try elf.ensureUnusedRelocCapacity(node, 1); |
| 2255 | | elf.addRelocAssumeCapacity( |
| 2341 | try elf.addRelocAssumeCapacity( |
| 2256 | 2342 | node, |
| 2257 | 2343 | reloc_info.offset, |
| 2258 | 2344 | target_sym, |
| ... | ... | @@ -2511,6 +2597,8 @@ fn create( |
| 2511 | 2597 | .strong_undef = .empty, |
| 2512 | 2598 | .weak_undef = .empty, |
| 2513 | 2599 | }, |
| 2600 | .copied_globals = .empty, |
| 2601 | .want_copied_globals = .empty, |
| 2514 | 2602 | .node_global_symbols = .empty, |
| 2515 | 2603 | .dso_globals = .empty, |
| 2516 | 2604 | .shstrtab = .{ .map = .empty }, |
| ... | ... | @@ -2558,6 +2646,8 @@ pub fn deinit(elf: *Elf) void { |
| 2558 | 2646 | elf.globals.weak_def.deinit(gpa); |
| 2559 | 2647 | elf.globals.strong_undef.deinit(gpa); |
| 2560 | 2648 | elf.globals.weak_undef.deinit(gpa); |
| 2649 | elf.copied_globals.deinit(gpa); |
| 2650 | elf.want_copied_globals.deinit(gpa); |
| 2561 | 2651 | elf.node_global_symbols.deinit(gpa); |
| 2562 | 2652 | elf.dso_globals.deinit(gpa); |
| 2563 | 2653 | elf.shstrtab.map.deinit(gpa); |
| ... | ... | @@ -3117,14 +3207,14 @@ fn initHeaders( |
| 3117 | 3207 | }); |
| 3118 | 3208 | elf.plt_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len); |
| 3119 | 3209 | try elf.ensureUnusedRelocCapacity(plt_ni, 2); |
| 3120 | | elf.addRelocAssumeCapacity( |
| 3210 | try elf.addRelocAssumeCapacity( |
| 3121 | 3211 | plt_ni, |
| 3122 | 3212 | 2, |
| 3123 | 3213 | got_plt_sym, |
| 3124 | 3214 | 8 * 1 - 4, |
| 3125 | 3215 | .{ .X86_64 = .PC32 }, |
| 3126 | 3216 | ); |
| 3127 | | elf.addRelocAssumeCapacity( |
| 3217 | try elf.addRelocAssumeCapacity( |
| 3128 | 3218 | plt_ni, |
| 3129 | 3219 | 8, |
| 3130 | 3220 | got_plt_sym, |
| ... | ... | @@ -3267,7 +3357,7 @@ pub fn endProgress(elf: *Elf) void { |
| 3267 | 3357 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 3268 | 3358 | return elf.nodes.get(@intFromEnum(ni)); |
| 3269 | 3359 | } |
| 3270 | | /// Asserts that `ni` is a section, input section, NAV, UAV, or lazy code/data. |
| 3360 | /// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data. |
| 3271 | 3361 | fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { |
| 3272 | 3362 | return switch (elf.getNode(ni)) { |
| 3273 | 3363 | .file => unreachable, |
| ... | ... | @@ -3278,6 +3368,7 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { |
| 3278 | 3368 | .section => |shndx| shndx, |
| 3279 | 3369 | |
| 3280 | 3370 | .input_section, |
| 3371 | .copied_global, |
| 3281 | 3372 | .nav, |
| 3282 | 3373 | .uav, |
| 3283 | 3374 | .lazy_code, |
| ... | ... | @@ -3294,6 +3385,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 3294 | 3385 | }, |
| 3295 | 3386 | .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), |
| 3296 | 3387 | .input_section => unreachable, |
| 3388 | .copied_global => unreachable, |
| 3297 | 3389 | inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 3298 | 3390 | }; |
| 3299 | 3391 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); |
| ... | ... | @@ -3312,6 +3404,7 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 3312 | 3404 | .shdr => unreachable, // cannot contain relocs |
| 3313 | 3405 | .segment => unreachable, // cannot contain relocs |
| 3314 | 3406 | .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) |
| 3407 | .copied_global => unreachable, // cannot contain relocs |
| 3315 | 3408 | .input_section => |isi| .{ |
| 3316 | 3409 | &elf.input_sections.items[@intFromEnum(isi)].first_symbol_reloc, |
| 3317 | 3410 | &elf.input_sections.items[@intFromEnum(isi)].first_got_reloc, |
| ... | ... | @@ -4270,7 +4363,7 @@ fn loadObject( |
| 4270 | 4363 | .{rel.info.sym}, |
| 4271 | 4364 | ); |
| 4272 | 4365 | } |
| 4273 | | elf.addRelocAssumeCapacity( |
| 4366 | try elf.addRelocAssumeCapacity( |
| 4274 | 4367 | loc_node, |
| 4275 | 4368 | rel.offset - loc_sec.shdr.addr, |
| 4276 | 4369 | target, |
| ... | ... | @@ -4303,12 +4396,19 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 4303 | 4396 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 4304 | 4397 | return diags.failParse(path, "bad machine", .{}); |
| 4305 | 4398 | if (ehdr.shnum > 0) try fr.seekTo(ehdr.shoff); |
| 4399 | // We're going to need to know the alignment of every section later. |
| 4400 | const section_aligns = try gpa.alloc(std.mem.Alignment, ehdr.shnum); |
| 4401 | defer gpa.free(section_aligns); |
| 4306 | 4402 | const dynamic_sh: ElfN.Shdr, const dynsym_sh: ElfN.Shdr = sh: { |
| 4307 | 4403 | var dynamic_sh: ?ElfN.Shdr = null; |
| 4308 | 4404 | var dynsym_sh: ?ElfN.Shdr = null; |
| 4309 | | for (0..ehdr.shnum) |_| { |
| 4405 | for (section_aligns) |*section_align| { |
| 4310 | 4406 | const sh = try r.peekStruct(ElfN.Shdr, target_endian); |
| 4311 | 4407 | try r.discardAll(ehdr.shentsize); |
| 4408 | section_align.* = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| 4409 | usize, |
| 4410 | @intCast(@max(sh.addralign, 1)), |
| 4411 | )); |
| 4312 | 4412 | switch (sh.type) { |
| 4313 | 4413 | else => {}, |
| 4314 | 4414 | .DYNAMIC => dynamic_sh = sh, |
| ... | ... | @@ -4395,17 +4495,51 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 4395 | 4495 | } |
| 4396 | 4496 | |
| 4397 | 4497 | if (sym.shndx == std.elf.SHN_UNDEF) continue; |
| 4498 | if (sym.shndx >= ehdr.shnum) continue; |
| 4398 | 4499 | |
| 4399 | 4500 | if (sym.name >= dynstr.len) { |
| 4400 | 4501 | return diags.failParse(path, "bad symbol name string", .{}); |
| 4401 | 4502 | } |
| 4402 | 4503 | |
| 4504 | // We need to guess the worst-case alignment of the symbol. Yes, I know this seems |
| 4505 | // insane---refer to the doc comment on `alignment` in `Elf.dso_globals`. |
| 4506 | const sym_align: std.mem.Alignment = switch (sym.value) { |
| 4507 | 0 => section_aligns[sym.shndx], |
| 4508 | else => section_aligns[sym.shndx].min(@enumFromInt(@ctz(sym.value))), |
| 4509 | }; |
| 4510 | |
| 4403 | 4511 | const name = try elf.string(.strtab, std.mem.sliceTo(dynstr[sym.name..], 0)); |
| 4404 | 4512 | const gop = elf.dso_globals.getOrPutAssumeCapacity(name); |
| 4405 | | if (!gop.found_existing or gop.value_ptr.* == .NOTYPE) { |
| 4406 | | gop.value_ptr.* = sym.info.type; |
| 4513 | |
| 4514 | if (gop.found_existing and gop.value_ptr.type != .NOTYPE) { |
| 4515 | if (sym.size > gop.value_ptr.size or |
| 4516 | sym_align.compare(.gt, gop.value_ptr.alignment)) |
| 4517 | { |
| 4518 | gop.value_ptr.size = @max(gop.value_ptr.size, sym.size); |
| 4519 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(sym_align); |
| 4520 | if (elf.copied_globals.get(name)) |copied_global| { |
| 4521 | // We have a copy relocation for this global, but the amount of space we |
| 4522 | // reserved for it could be too small or underaligned! |
| 4523 | try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); |
| 4524 | try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment); |
| 4525 | const global_ptr = elf.globalByName(name).?; |
| 4526 | switch (elf.symPtr(global_ptr.symtab_index)) { |
| 4527 | inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)), |
| 4528 | } |
| 4529 | switch (elf.dynsymPtr(global_ptr.dynsym_index)) { |
| 4530 | inline else => |dynsym_ptr| elf.targetStore(&dynsym_ptr.size, @intCast(gop.value_ptr.size)), |
| 4531 | } |
| 4532 | } |
| 4533 | } |
| 4534 | continue; |
| 4407 | 4535 | } |
| 4408 | 4536 | |
| 4537 | gop.value_ptr.* = .{ |
| 4538 | .type = sym.info.type, |
| 4539 | .size = sym.size, |
| 4540 | .alignment = sym_align, |
| 4541 | }; |
| 4542 | |
| 4409 | 4543 | // If there's already an undefined symbol by this name of type STT_NOTYPE, populate |
| 4410 | 4544 | // its type now. |
| 4411 | 4545 | const global_ptr = elf.globals.strong_undef.getPtr(name) orelse |
| ... | ... | @@ -4414,14 +4548,20 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 4414 | 4548 | |
| 4415 | 4549 | if (global_ptr.dynsym_index == 0) continue; |
| 4416 | 4550 | |
| 4551 | if (elf.want_copied_globals.swapRemove(name)) { |
| 4552 | // We just found a DSO definition of a symbol for which we wanted a copy |
| 4553 | // relocation, so add one if we can! |
| 4554 | _ = try elf.maybeAddCopyRelocation(name); |
| 4555 | } |
| 4556 | |
| 4417 | 4557 | const sym_ptr = @field(elf.symPtr(global_ptr.symtab_index), @tagName(class)); |
| 4558 | errdefer comptime unreachable; // messing with the output file could invalidate `sym_ptr` |
| 4559 | |
| 4418 | 4560 | switch (elf.targetLoad(&sym_ptr.other).visibility) { |
| 4419 | 4561 | .HIDDEN, .INTERNAL, .PROTECTED => continue, |
| 4420 | 4562 | .DEFAULT => {}, |
| 4421 | 4563 | } |
| 4422 | 4564 | |
| 4423 | | if (elf.targetLoad(&sym_ptr.shndx) != std.elf.SHN_UNDEF) continue; |
| 4424 | | |
| 4425 | 4565 | const cur_info = elf.targetLoad(&sym_ptr.info); |
| 4426 | 4566 | if (cur_info.type == .NOTYPE) { |
| 4427 | 4567 | const new_type: std.elf.STT = switch (sym.info.type) { |
| ... | ... | @@ -4440,9 +4580,8 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) !void { |
| 4440 | 4580 | .type = new_type, |
| 4441 | 4581 | }); |
| 4442 | 4582 | |
| 4443 | | // If we just turned this into an STT_FUNC symbol, then we have determined |
| 4444 | | // that it needs a PLT entry. |
| 4445 | 4583 | if (new_type == .FUNC) { |
| 4584 | // We turned STT_NOTYPE into STT_FUNC, so we now need a PLT entry... |
| 4446 | 4585 | elf.addPltEntry(name, global_ptr.dynsym_index); |
| 4447 | 4586 | // ...and therefore, we need to re-apply that symbol's relocations, as |
| 4448 | 4587 | // some might be targeting its PLT entry. |
| ... | ... | @@ -4630,6 +4769,9 @@ fn prelinkInner(elf: *Elf) !void { |
| 4630 | 4769 | } |
| 4631 | 4770 | break :rpath try elf.string(.dynstr, buf.items); |
| 4632 | 4771 | }; |
| 4772 | const soname: ?String(.dynstr) = if (elf.options.soname) |soname_slice| str: { |
| 4773 | break :str try elf.string(.dynstr, soname_slice); |
| 4774 | } else null; |
| 4633 | 4775 | const needed_len = elf.needed.count(); |
| 4634 | 4776 | const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + |
| 4635 | 4777 | @intFromBool(rpath != .empty) + |
| ... | ... | @@ -4644,141 +4786,155 @@ fn prelinkInner(elf: *Elf) !void { |
| 4644 | 4786 | switch (elf.shdrPtr(elf.shndx.dynamic)) { |
| 4645 | 4787 | inline else => |shdr| elf.targetStore(&shdr.size, dynamic_size), |
| 4646 | 4788 | } |
| 4647 | | const sec_dynamic = dynamic_ni.slice(&elf.mf); |
| 4648 | | const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic)); |
| 4649 | | var dynamic_index: usize = 0; |
| 4650 | | for ( |
| 4651 | | dynamic_entries[dynamic_index..][0..needed_len], |
| 4652 | | elf.needed.keys(), |
| 4653 | | ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, @intFromEnum(needed) }; |
| 4654 | | dynamic_index += needed_len; |
| 4655 | | if (elf.options.soname) |soname| { |
| 4656 | | dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, @intFromEnum(try elf.string(.dynstr, soname)) }; |
| 4657 | | dynamic_index += 1; |
| 4658 | | } |
| 4659 | | if (rpath != .empty) { |
| 4660 | | dynamic_entries[dynamic_index] = .{ std.elf.DT_RUNPATH, @intFromEnum(rpath) }; |
| 4661 | | dynamic_index += 1; |
| 4662 | | } |
| 4663 | | if (flags != 0) { |
| 4664 | | dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS, flags }; |
| 4665 | | dynamic_index += 1; |
| 4666 | | } |
| 4667 | | if (flags_1 != 0) { |
| 4668 | | dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS_1, flags_1 }; |
| 4669 | | dynamic_index += 1; |
| 4670 | | } |
| 4671 | | if (comp.config.output_mode == .Exe) { |
| 4672 | | dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 }; |
| 4673 | | dynamic_index += 1; |
| 4674 | | } |
| 4675 | | if (elf.shndx.init_array != .UNDEF) { |
| 4676 | | dynamic_entries[dynamic_index..][0..2].* = .{ |
| 4677 | | .{ std.elf.DT_INIT_ARRAY, @intCast(elf.shndx.init_array.vaddr(elf)) }, |
| 4678 | | .{ std.elf.DT_INIT_ARRAYSZ, elf.targetLoad( |
| 4679 | | &@field(elf.shdrPtr(elf.shndx.init_array), @tagName(ct_class)).size, |
| 4789 | |
| 4790 | const dynamic_indices: struct { |
| 4791 | init_array: ?usize, |
| 4792 | fini_array: ?usize, |
| 4793 | preinit_array: ?usize, |
| 4794 | } = indices: { |
| 4795 | const sec_dynamic = dynamic_ni.slice(&elf.mf); |
| 4796 | const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic)); |
| 4797 | errdefer comptime unreachable; // don't invalidate `dynamic_entries` |
| 4798 | var dynamic_index: usize = 0; |
| 4799 | for ( |
| 4800 | dynamic_entries[dynamic_index..][0..needed_len], |
| 4801 | elf.needed.keys(), |
| 4802 | ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, @intFromEnum(needed) }; |
| 4803 | dynamic_index += needed_len; |
| 4804 | if (soname) |soname_dynstr| { |
| 4805 | dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, @intFromEnum(soname_dynstr) }; |
| 4806 | dynamic_index += 1; |
| 4807 | } |
| 4808 | if (rpath != .empty) { |
| 4809 | dynamic_entries[dynamic_index] = .{ std.elf.DT_RUNPATH, @intFromEnum(rpath) }; |
| 4810 | dynamic_index += 1; |
| 4811 | } |
| 4812 | if (flags != 0) { |
| 4813 | dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS, flags }; |
| 4814 | dynamic_index += 1; |
| 4815 | } |
| 4816 | if (flags_1 != 0) { |
| 4817 | dynamic_entries[dynamic_index] = .{ std.elf.DT_FLAGS_1, flags_1 }; |
| 4818 | dynamic_index += 1; |
| 4819 | } |
| 4820 | if (comp.config.output_mode == .Exe) { |
| 4821 | dynamic_entries[dynamic_index] = .{ std.elf.DT_DEBUG, 0 }; |
| 4822 | dynamic_index += 1; |
| 4823 | } |
| 4824 | const init_array_index: ?usize = if (elf.shndx.init_array != .UNDEF) i: { |
| 4825 | dynamic_entries[dynamic_index..][0..2].* = .{ |
| 4826 | .{ std.elf.DT_INIT_ARRAY, @intCast(elf.shndx.init_array.vaddr(elf)) }, |
| 4827 | .{ std.elf.DT_INIT_ARRAYSZ, elf.targetLoad( |
| 4828 | &@field(elf.shdrPtr(elf.shndx.init_array), @tagName(ct_class)).size, |
| 4829 | ) }, |
| 4830 | }; |
| 4831 | defer dynamic_index += 2; |
| 4832 | break :i dynamic_index; |
| 4833 | } else null; |
| 4834 | const fini_array_index: ?usize = if (elf.shndx.fini_array != .UNDEF) i: { |
| 4835 | dynamic_entries[dynamic_index..][0..2].* = .{ |
| 4836 | .{ std.elf.DT_FINI_ARRAY, @intCast(elf.shndx.fini_array.vaddr(elf)) }, |
| 4837 | .{ std.elf.DT_FINI_ARRAYSZ, elf.targetLoad( |
| 4838 | &@field(elf.shdrPtr(elf.shndx.fini_array), @tagName(ct_class)).size, |
| 4839 | ) }, |
| 4840 | }; |
| 4841 | defer dynamic_index += 2; |
| 4842 | break :i dynamic_index; |
| 4843 | } else null; |
| 4844 | const preinit_array_index: ?usize = if (elf.shndx.preinit_array != .UNDEF) i: { |
| 4845 | dynamic_entries[dynamic_index..][0..2].* = .{ |
| 4846 | .{ std.elf.DT_PREINIT_ARRAY, @intCast(elf.shndx.preinit_array.vaddr(elf)) }, |
| 4847 | .{ std.elf.DT_PREINIT_ARRAYSZ, elf.targetLoad( |
| 4848 | &@field(elf.shdrPtr(elf.shndx.preinit_array), @tagName(ct_class)).size, |
| 4849 | ) }, |
| 4850 | }; |
| 4851 | defer dynamic_index += 2; |
| 4852 | break :i dynamic_index; |
| 4853 | } else null; |
| 4854 | dynamic_entries[dynamic_index..][0..12].* = .{ |
| 4855 | .{ std.elf.DT_RELA, @intCast(elf.shndx.rela_dyn.vaddr(elf)) }, |
| 4856 | .{ std.elf.DT_RELASZ, elf.targetLoad( |
| 4857 | &@field(elf.shdrPtr(elf.shndx.rela_dyn), @tagName(ct_class)).size, |
| 4680 | 4858 | ) }, |
| 4681 | | }; |
| 4682 | | try elf.ensureUnusedRelocCapacity(dynamic_ni, 1); |
| 4683 | | elf.addRelocAssumeCapacity( |
| 4684 | | dynamic_ni, |
| 4685 | | @sizeOf(ElfN.Addr) * (2 * dynamic_index + 1), |
| 4686 | | .local(elf.shndx.init_array.get(elf).lsi), |
| 4687 | | 0, |
| 4688 | | .absAddr(elf), |
| 4689 | | ); |
| 4690 | | dynamic_index += 2; |
| 4691 | | } |
| 4692 | | if (elf.shndx.fini_array != .UNDEF) { |
| 4693 | | dynamic_entries[dynamic_index..][0..2].* = .{ |
| 4694 | | .{ std.elf.DT_FINI_ARRAY, @intCast(elf.shndx.fini_array.vaddr(elf)) }, |
| 4695 | | .{ std.elf.DT_FINI_ARRAYSZ, elf.targetLoad( |
| 4696 | | &@field(elf.shdrPtr(elf.shndx.fini_array), @tagName(ct_class)).size, |
| 4859 | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, |
| 4860 | .{ std.elf.DT_JMPREL, @intCast(elf.shndx.rela_plt.vaddr(elf)) }, |
| 4861 | .{ std.elf.DT_PLTRELSZ, elf.targetLoad( |
| 4862 | &@field(elf.shdrPtr(elf.shndx.rela_plt), @tagName(ct_class)).size, |
| 4697 | 4863 | ) }, |
| 4698 | | }; |
| 4699 | | try elf.ensureUnusedRelocCapacity(dynamic_ni, 1); |
| 4700 | | elf.addRelocAssumeCapacity( |
| 4701 | | dynamic_ni, |
| 4702 | | @sizeOf(ElfN.Addr) * (2 * dynamic_index + 1), |
| 4703 | | .local(elf.shndx.fini_array.get(elf).lsi), |
| 4704 | | 0, |
| 4705 | | .absAddr(elf), |
| 4706 | | ); |
| 4707 | | dynamic_index += 2; |
| 4708 | | } |
| 4709 | | if (elf.shndx.preinit_array != .UNDEF) { |
| 4710 | | dynamic_entries[dynamic_index..][0..2].* = .{ |
| 4711 | | .{ std.elf.DT_PREINIT_ARRAY, @intCast(elf.shndx.preinit_array.vaddr(elf)) }, |
| 4712 | | .{ std.elf.DT_PREINIT_ARRAYSZ, elf.targetLoad( |
| 4713 | | &@field(elf.shdrPtr(elf.shndx.preinit_array), @tagName(ct_class)).size, |
| 4864 | .{ std.elf.DT_PLTGOT, @intCast(elf.shndx.got_plt.vaddr(elf)) }, |
| 4865 | .{ std.elf.DT_PLTREL, std.elf.DT_RELA }, |
| 4866 | .{ std.elf.DT_SYMTAB, @intCast(elf.shndx.dynsym.vaddr(elf)) }, |
| 4867 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, |
| 4868 | .{ std.elf.DT_STRTAB, @intCast(elf.shndx.dynstr.vaddr(elf)) }, |
| 4869 | .{ std.elf.DT_STRSZ, elf.targetLoad( |
| 4870 | &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size, |
| 4714 | 4871 | ) }, |
| 4872 | .{ std.elf.DT_NULL, 0 }, |
| 4873 | }; |
| 4874 | dynamic_index += 12; |
| 4875 | assert(dynamic_index == dynamic_len); |
| 4876 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| |
| 4877 | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); |
| 4878 | |
| 4879 | break :indices .{ |
| 4880 | .init_array = init_array_index, |
| 4881 | .fini_array = fini_array_index, |
| 4882 | .preinit_array = preinit_array_index, |
| 4715 | 4883 | }; |
| 4716 | | try elf.ensureUnusedRelocCapacity(dynamic_ni, 1); |
| 4717 | | elf.addRelocAssumeCapacity( |
| 4718 | | dynamic_ni, |
| 4719 | | @sizeOf(ElfN.Addr) * (2 * dynamic_index + 1), |
| 4720 | | .local(elf.shndx.preinit_array.get(elf).lsi), |
| 4721 | | 0, |
| 4722 | | .absAddr(elf), |
| 4723 | | ); |
| 4724 | | dynamic_index += 2; |
| 4725 | | } |
| 4726 | | dynamic_entries[dynamic_index..][0..12].* = .{ |
| 4727 | | .{ std.elf.DT_RELA, @intCast(elf.shndx.rela_dyn.vaddr(elf)) }, |
| 4728 | | .{ std.elf.DT_RELASZ, elf.targetLoad( |
| 4729 | | &@field(elf.shdrPtr(elf.shndx.rela_dyn), @tagName(ct_class)).size, |
| 4730 | | ) }, |
| 4731 | | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, |
| 4732 | | .{ std.elf.DT_JMPREL, @intCast(elf.shndx.rela_plt.vaddr(elf)) }, |
| 4733 | | .{ std.elf.DT_PLTRELSZ, elf.targetLoad( |
| 4734 | | &@field(elf.shdrPtr(elf.shndx.rela_plt), @tagName(ct_class)).size, |
| 4735 | | ) }, |
| 4736 | | .{ std.elf.DT_PLTGOT, @intCast(elf.shndx.got_plt.vaddr(elf)) }, |
| 4737 | | .{ std.elf.DT_PLTREL, std.elf.DT_RELA }, |
| 4738 | | .{ std.elf.DT_SYMTAB, @intCast(elf.shndx.dynsym.vaddr(elf)) }, |
| 4739 | | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, |
| 4740 | | .{ std.elf.DT_STRTAB, @intCast(elf.shndx.dynstr.vaddr(elf)) }, |
| 4741 | | .{ std.elf.DT_STRSZ, elf.targetLoad( |
| 4742 | | &@field(elf.shdrPtr(elf.shndx.dynstr), @tagName(ct_class)).size, |
| 4743 | | ) }, |
| 4744 | | .{ std.elf.DT_NULL, 0 }, |
| 4745 | 4884 | }; |
| 4746 | | dynamic_index += 12; |
| 4747 | | assert(dynamic_index == dynamic_len); |
| 4748 | | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| |
| 4749 | | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); |
| 4750 | 4885 | |
| 4751 | 4886 | elf.dynamic_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len); |
| 4752 | | try elf.ensureUnusedRelocCapacity(dynamic_ni, 5); |
| 4753 | | elf.addRelocAssumeCapacity( |
| 4887 | try elf.ensureUnusedRelocCapacity(dynamic_ni, 8); |
| 4888 | if (dynamic_indices.init_array) |index| try elf.addRelocAssumeCapacity( |
| 4889 | dynamic_ni, |
| 4890 | @sizeOf(ElfN.Addr) * (2 * index + 1), |
| 4891 | .local(elf.shndx.init_array.get(elf).lsi), |
| 4892 | 0, |
| 4893 | .absAddr(elf), |
| 4894 | ); |
| 4895 | if (dynamic_indices.fini_array) |index| try elf.addRelocAssumeCapacity( |
| 4896 | dynamic_ni, |
| 4897 | @sizeOf(ElfN.Addr) * (2 * index + 1), |
| 4898 | .local(elf.shndx.fini_array.get(elf).lsi), |
| 4899 | 0, |
| 4900 | .absAddr(elf), |
| 4901 | ); |
| 4902 | if (dynamic_indices.preinit_array) |index| try elf.addRelocAssumeCapacity( |
| 4903 | dynamic_ni, |
| 4904 | @sizeOf(ElfN.Addr) * (2 * index + 1), |
| 4905 | .local(elf.shndx.preinit_array.get(elf).lsi), |
| 4906 | 0, |
| 4907 | .absAddr(elf), |
| 4908 | ); |
| 4909 | try elf.addRelocAssumeCapacity( |
| 4754 | 4910 | dynamic_ni, |
| 4755 | 4911 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 12) + 1), |
| 4756 | 4912 | .local(elf.shndx.rela_dyn.get(elf).lsi), |
| 4757 | 4913 | 0, |
| 4758 | 4914 | .absAddr(elf), |
| 4759 | 4915 | ); |
| 4760 | | elf.addRelocAssumeCapacity( |
| 4916 | try elf.addRelocAssumeCapacity( |
| 4761 | 4917 | dynamic_ni, |
| 4762 | 4918 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 9) + 1), |
| 4763 | 4919 | .local(elf.shndx.rela_plt.get(elf).lsi), |
| 4764 | 4920 | 0, |
| 4765 | 4921 | .absAddr(elf), |
| 4766 | 4922 | ); |
| 4767 | | elf.addRelocAssumeCapacity( |
| 4923 | try elf.addRelocAssumeCapacity( |
| 4768 | 4924 | dynamic_ni, |
| 4769 | 4925 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 7) + 1), |
| 4770 | 4926 | .local(elf.shndx.got_plt.get(elf).lsi), |
| 4771 | 4927 | 0, |
| 4772 | 4928 | .absAddr(elf), |
| 4773 | 4929 | ); |
| 4774 | | elf.addRelocAssumeCapacity( |
| 4930 | try elf.addRelocAssumeCapacity( |
| 4775 | 4931 | dynamic_ni, |
| 4776 | 4932 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1), |
| 4777 | 4933 | .local(elf.shndx.dynsym.get(elf).lsi), |
| 4778 | 4934 | 0, |
| 4779 | 4935 | .absAddr(elf), |
| 4780 | 4936 | ); |
| 4781 | | elf.addRelocAssumeCapacity( |
| 4937 | try elf.addRelocAssumeCapacity( |
| 4782 | 4938 | dynamic_ni, |
| 4783 | 4939 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1), |
| 4784 | 4940 | .local(elf.shndx.dynstr.get(elf).lsi), |
| ... | ... | @@ -4951,6 +5107,8 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 4951 | 5107 | }, |
| 4952 | 5108 | } |
| 4953 | 5109 | } |
| 5110 | /// Although this function requires a preceding call to `ensureUnusedRelocCapacity`, it is still |
| 5111 | /// fallible, because there are some rare cases for which we cannot reserve capacity upfront. |
| 4954 | 5112 | fn addRelocAssumeCapacity( |
| 4955 | 5113 | elf: *Elf, |
| 4956 | 5114 | node: MappedFile.Node.Index, |
| ... | ... | @@ -4958,7 +5116,7 @@ fn addRelocAssumeCapacity( |
| 4958 | 5116 | target: Symbol.Id, |
| 4959 | 5117 | addend: i64, |
| 4960 | 5118 | @"type": MachineRelocType, |
| 4961 | | ) void { |
| 5119 | ) !void { |
| 4962 | 5120 | assert(node != .none); |
| 4963 | 5121 | switch (elf.ehdrField(.type)) { |
| 4964 | 5122 | .NONE, .CORE, _ => unreachable, |
| ... | ... | @@ -5021,25 +5179,25 @@ fn addRelocAssumeCapacity( |
| 5021 | 5179 | .TLSDESC => @panic("TODO: R_X86_64_TLSDESC"), |
| 5022 | 5180 | |
| 5023 | 5181 | // Relocations targeting a symbol |
| 5024 | | .@"64" => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs64), |
| 5025 | | .@"32" => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32), |
| 5026 | | .@"32S" => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32s), |
| 5027 | | .PC64 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64), |
| 5028 | | .PC32 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32), |
| 5029 | | .PLT32 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .pltrel32), |
| 5030 | | .SIZE64 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .size64), |
| 5031 | | .SIZE32 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .size32), |
| 5032 | | .DTPOFF64 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .dtpoff64), |
| 5033 | | .DTPOFF32 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .dtpoff32), |
| 5034 | | .TPOFF64 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64), |
| 5035 | | .TPOFF32 => elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32), |
| 5182 | .@"64" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs64), |
| 5183 | .@"32" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32), |
| 5184 | .@"32S" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32s), |
| 5185 | .PC64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64), |
| 5186 | .PC32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32), |
| 5187 | .PLT32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .pltrel32), |
| 5188 | .SIZE64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .size64), |
| 5189 | .SIZE32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .size32), |
| 5190 | .DTPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .dtpoff64), |
| 5191 | .DTPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .dtpoff32), |
| 5192 | .TPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64), |
| 5193 | .TPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32), |
| 5036 | 5194 | .GOTPC64 => { |
| 5037 | 5195 | const got_sym: Symbol.Id = .local(elf.shndx.got.get(elf).lsi); |
| 5038 | | return elf.addSymbolRelocAssumeCapacity(node, offset, got_sym, addend, .rel64); |
| 5196 | try elf.addSymbolRelocAssumeCapacity(node, offset, got_sym, addend, .rel64); |
| 5039 | 5197 | }, |
| 5040 | 5198 | .GOTPC32 => { |
| 5041 | 5199 | const got_sym: Symbol.Id = .local(elf.shndx.got.get(elf).lsi); |
| 5042 | | return elf.addSymbolRelocAssumeCapacity(node, offset, got_sym, addend, .rel32); |
| 5200 | try elf.addSymbolRelocAssumeCapacity(node, offset, got_sym, addend, .rel32); |
| 5043 | 5201 | }, |
| 5044 | 5202 | |
| 5045 | 5203 | // TODO: these are the address of an arbitrary symbol (or PLT entry) relative to the |
| ... | ... | @@ -5077,11 +5235,16 @@ fn addSymbolRelocAssumeCapacity( |
| 5077 | 5235 | target: Symbol.Id, |
| 5078 | 5236 | addend: i64, |
| 5079 | 5237 | @"type": SymbolReloc.Type, |
| 5080 | | ) void { |
| 5238 | ) !void { |
| 5081 | 5239 | assert(elf.ehdrField(.type) != .REL); |
| 5082 | 5240 | |
| 5083 | 5241 | const rela_index: Section.RelaIndex.Optional = r: { |
| 5084 | 5242 | if (elf.shndx.dynamic == .UNDEF) break :r .none; |
| 5243 | const global_name = switch (target.unwrap()) { |
| 5244 | .local => break :r .none, |
| 5245 | .global => |name| name, |
| 5246 | }; |
| 5247 | |
| 5085 | 5248 | const rela_type: MachineRelocType = switch (elf.ehdrField(.machine)) { |
| 5086 | 5249 | else => |machine| @panic(@tagName(machine)), |
| 5087 | 5250 | .X86_64 => .{ .X86_64 = switch (@"type") { |
| ... | ... | @@ -5101,21 +5264,31 @@ fn addSymbolRelocAssumeCapacity( |
| 5101 | 5264 | .size32 => .SIZE32, |
| 5102 | 5265 | } }, |
| 5103 | 5266 | }; |
| 5104 | | const dynsym_index: u32 = switch (target.unwrap()) { |
| 5105 | | .local => break :r .none, |
| 5106 | | // TODO: even if the symbol is locally defined, preemption/interposition is a |
| 5107 | | // possibility, which this condition does not currently consider! |
| 5108 | | .global => |name| if (elf.globals.strong_def.contains(name) or |
| 5109 | | elf.globals.weak_def.contains(name)) |
| 5110 | | { |
| 5111 | | break :r .none; |
| 5112 | | } else elf.globalByName(name).?.dynsym_index, |
| 5113 | | }; |
| 5267 | // TODO: even if the symbol is locally defined, preemption/interposition is a |
| 5268 | // possibility, which this condition does not currently consider! |
| 5269 | if (elf.globals.strong_def.contains(global_name) or |
| 5270 | elf.globals.weak_def.contains(global_name)) |
| 5271 | { |
| 5272 | break :r .none; |
| 5273 | } |
| 5274 | |
| 5275 | const dynsym_index = elf.globalByName(global_name).?.dynsym_index; |
| 5276 | if (dynsym_index == 0) break :r .none; |
| 5114 | 5277 | |
| 5115 | 5278 | switch (elf.nodeWantsDsoRelocation(node)) { |
| 5116 | 5279 | .no => break :r .none, |
| 5117 | 5280 | .yes => {}, |
| 5118 | | .yes_textrel => elf.textrel_count += 1, |
| 5281 | .yes_textrel => if (try elf.maybeAddCopyRelocation(global_name)) { |
| 5282 | // We were able to use a copy relocation on this symbol to avoid a text relocation, |
| 5283 | // which is apparently considered a good thing despite copy relocations being an |
| 5284 | // abomination. (This is necessary for correctness in some cases, because e.g. a |
| 5285 | // 32-bit runtime relocation on a 64-bit target will often cause rtld errors due to |
| 5286 | // the DSOs being loaded too far apart.) |
| 5287 | break :r .none; |
| 5288 | } else { |
| 5289 | // At least for now, our only choice is a text relocation. |
| 5290 | elf.textrel_count += 1; |
| 5291 | }, |
| 5119 | 5292 | } |
| 5120 | 5293 | |
| 5121 | 5294 | // It currently looks like we need a runtime relocation for this. |
| ... | ... | @@ -5175,6 +5348,7 @@ fn addGotRelocAssumeCapacity( |
| 5175 | 5348 | .ehdr => unreachable, // cannot contain relocs |
| 5176 | 5349 | .shdr => unreachable, // cannot contain relocs |
| 5177 | 5350 | .segment => unreachable, // cannot contain relocs |
| 5351 | .copied_global => unreachable, // cannot contain relocs |
| 5178 | 5352 | } |
| 5179 | 5353 | |
| 5180 | 5354 | const gop = elf.got.getOrPutAssumeCapacity(target); |
| ... | ... | @@ -5275,29 +5449,37 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 5275 | 5449 | .global => |name| name, |
| 5276 | 5450 | }; |
| 5277 | 5451 | // If the symbol is *defined* in this module, we might be able to avoid the relocation. |
| 5278 | | if (elf.globals.strong_def.getPtr(name) orelse |
| 5279 | | elf.globals.weak_def.getPtr(name)) |global| |
| 5280 | | { |
| 5452 | const need_reloc: bool = need_reloc: { |
| 5453 | const global = g: { |
| 5454 | if (elf.globals.strong_def.getPtr(name)) |g| break :g g; |
| 5455 | if (elf.globals.weak_def.getPtr(name)) |g| break :g g; |
| 5456 | // The global is undefined, which probably means we need a relocation---unless |
| 5457 | // we have created a copy relocation for it, in which case we own the canonical |
| 5458 | // address of this symbol in this DSO! |
| 5459 | break :need_reloc !elf.copied_globals.contains(name); |
| 5460 | }; |
| 5461 | |
| 5281 | 5462 | // We have a definition, but it might be interposable (aka preemptible). There |
| 5282 | 5463 | // are two cases where it is not and so we can (and, in fact, must) elide the |
| 5283 | 5464 | // runtime relocation: |
| 5284 | 5465 | // * We are the executable. Symbols from executables cannot be interposed. |
| 5285 | 5466 | // * The symbol's visibility disallows interposition. |
| 5286 | 5467 | if (elf.base.comp.config.output_mode == .Exe) { |
| 5287 | | // No relocation needed. |
| 5288 | | break :val .{ .unsigned = sym_id.value(elf) }; |
| 5468 | break :need_reloc false; |
| 5289 | 5469 | } |
| 5290 | 5470 | const visibility: std.elf.STV = switch (elf.symPtr(global.symtab_index)) { |
| 5291 | 5471 | inline else => |sym| elf.targetLoad(&sym.other).visibility, |
| 5292 | 5472 | }; |
| 5293 | | switch (visibility) { |
| 5294 | | .DEFAULT => {}, |
| 5295 | | .INTERNAL, .HIDDEN, .PROTECTED => { |
| 5296 | | // No relocation needed. |
| 5297 | | break :val .{ .unsigned = sym_id.value(elf) }; |
| 5298 | | }, |
| 5299 | | } |
| 5473 | break :need_reloc switch (visibility) { |
| 5474 | .DEFAULT => true, |
| 5475 | .INTERNAL, .HIDDEN, .PROTECTED => false, |
| 5476 | }; |
| 5477 | }; |
| 5478 | |
| 5479 | if (!need_reloc) { |
| 5480 | break :val .{ .unsigned = sym_id.value(elf) }; |
| 5300 | 5481 | } |
| 5482 | |
| 5301 | 5483 | break :val .{ .reloc = .{ |
| 5302 | 5484 | .type = if (tag == .symbol) .globDat(elf) else .dtpOffAddr(elf), |
| 5303 | 5485 | .dynsym_index = elf.globalByName(name).?.dynsym_index, |
| ... | ... | @@ -5403,6 +5585,80 @@ fn nodeWantsDsoRelocation(elf: *Elf, node: MappedFile.Node.Index) enum { yes, ye |
| 5403 | 5585 | return .yes; |
| 5404 | 5586 | } |
| 5405 | 5587 | |
| 5588 | /// If the given undefined global could have a copy relocation, creates that relocation if it does |
| 5589 | /// not already exist, and returns `true`. |
| 5590 | /// |
| 5591 | /// Returns `false` iff a copy relocation cannot currently be created for the global. If it may be |
| 5592 | /// possible in future, the symbol is added to `elf.want_copied_globals` so that the copy relocation |
| 5593 | /// will be created if and when we discover a suitable definition in an input DSO. |
| 5594 | /// |
| 5595 | /// If this function creates a new copy relocation, it will also update relocations targeting the |
| 5596 | /// global where needed---the caller does not need to do this. |
| 5597 | /// |
| 5598 | /// Asserts that `elf.shndx.dynamic != .UNDEF` and that `global_name` refers to an *undefined* global. |
| 5599 | fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) !bool { |
| 5600 | assert(elf.shndx.dynamic != .UNDEF); |
| 5601 | |
| 5602 | const gpa = elf.base.comp.gpa; |
| 5603 | |
| 5604 | const global_ptr = elf.globals.strong_undef.getPtr(global_name) orelse |
| 5605 | elf.globals.weak_undef.getPtr(global_name).?; |
| 5606 | |
| 5607 | assert(global_ptr.dynsym_index != 0); |
| 5608 | |
| 5609 | // Only dynamic executables may contain `R_*_COPY` relocations. |
| 5610 | if (elf.shndx.dynamic == .UNDEF) return false; |
| 5611 | if (elf.base.comp.config.output_mode != .Exe) return false; |
| 5612 | |
| 5613 | const dso_global = elf.dso_globals.get(global_name) orelse { |
| 5614 | // We do not have a definition to provide the correct size for the symbol. If a definition |
| 5615 | // is discovered in a later DSO, we may at that point be able to add a copy relocation. |
| 5616 | try elf.want_copied_globals.put(gpa, global_name, {}); |
| 5617 | return false; |
| 5618 | }; |
| 5619 | |
| 5620 | if (dso_global.type != .OBJECT) return false; |
| 5621 | |
| 5622 | const gop = try elf.copied_globals.getOrPut(gpa, global_name); |
| 5623 | if (gop.found_existing) return true; |
| 5624 | errdefer assert(elf.copied_globals.pop().?.key == global_name); |
| 5625 | |
| 5626 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 5627 | const node = try elf.mf.addLastChildNode(gpa, Section.Index.data.get(elf).ni, .{ |
| 5628 | .size = dso_global.size, |
| 5629 | .alignment = dso_global.alignment, |
| 5630 | }); |
| 5631 | errdefer comptime unreachable; |
| 5632 | |
| 5633 | const vaddr = elf.computeNodeVAddr(node); |
| 5634 | elf.nodes.appendAssumeCapacity(.{ .copied_global = global_name }); |
| 5635 | const rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ |
| 5636 | .type = .copy(elf), |
| 5637 | .offset = vaddr, |
| 5638 | .raw_sym_index = global_ptr.dynsym_index, |
| 5639 | .addend = 0, |
| 5640 | }); |
| 5641 | gop.value_ptr.* = .{ |
| 5642 | .node = node, |
| 5643 | .rela_index = rela_index, |
| 5644 | }; |
| 5645 | |
| 5646 | switch (elf.symPtr(global_ptr.symtab_index)) { |
| 5647 | inline else => |sym| elf.targetStore(&sym.size, @intCast(dso_global.size)), |
| 5648 | } |
| 5649 | switch (elf.dynsymPtr(global_ptr.dynsym_index)) { |
| 5650 | inline else => |dynsym| elf.targetStore(&dynsym.size, @intCast(dso_global.size)), |
| 5651 | } |
| 5652 | |
| 5653 | // Because we now have a copy relocation, any dynamic relocations which target this symbol are |
| 5654 | // now incorrect, since we now own the canonical address of the symbol. So delete those relocs |
| 5655 | // and then update the symbol's address (and re-apply relocations targeting it of course). |
| 5656 | Symbol.Id.global(global_name).deleteDynamicTargetRelocs(elf); |
| 5657 | Symbol.Id.global(global_name).flushMoved(elf, vaddr); |
| 5658 | |
| 5659 | return true; |
| 5660 | } |
| 5661 | |
| 5406 | 5662 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| 5407 | 5663 | elf.updateNavInner(pt, nav_index) catch |err| switch (err) { |
| 5408 | 5664 | error.OutOfMemory, |
| ... | ... | @@ -5561,10 +5817,8 @@ pub fn flush( |
| 5561 | 5817 | error.Canceled => |e| return e, |
| 5562 | 5818 | else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}), |
| 5563 | 5819 | }; |
| 5564 | | const global = elf.globalByName(sym_name_strtab) orelse break :entry 0; |
| 5565 | | switch (elf.symPtr(global.symtab_index)) { |
| 5566 | | inline else => |sym| break :entry elf.targetLoad(&sym.value), |
| 5567 | | } |
| 5820 | if (elf.globalByName(sym_name_strtab) == null) break :entry 0; |
| 5821 | break :entry Symbol.Id.global(sym_name_strtab).value(elf); |
| 5568 | 5822 | }; |
| 5569 | 5823 | switch (elf.ehdrPtr()) { |
| 5570 | 5824 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)), |
| ... | ... | @@ -5923,15 +6177,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 5923 | 6177 | assert(first_name != .empty); |
| 5924 | 6178 | var name = first_name; |
| 5925 | 6179 | while (name != .empty) { |
| 5926 | | const global = elf.globalByName(name).?; |
| 5927 | | const old_sym_addr: u64 = switch (elf.symPtr(global.symtab_index)) { |
| 5928 | | inline else => |sym| elf.targetLoad(&sym.value), |
| 5929 | | }; |
| 6180 | const old_sym_addr = Symbol.Id.global(name).value(elf); |
| 5930 | 6181 | Symbol.Id.global(name).flushMoved( |
| 5931 | 6182 | elf, |
| 5932 | 6183 | old_sym_addr - old_addr + addr, |
| 5933 | 6184 | ); |
| 5934 | | name = global.next_in_node; |
| 6185 | name = elf.globalByName(name).?.next_in_node; |
| 5935 | 6186 | } |
| 5936 | 6187 | } |
| 5937 | 6188 | |
| ... | ... | @@ -5968,18 +6219,20 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 5968 | 6219 | var lsi, const end_lsi = ii.localSymbolRange(elf); |
| 5969 | 6220 | while (lsi != end_lsi) : (lsi = @enumFromInt(@intFromEnum(lsi) + 1)) { |
| 5970 | 6221 | if (lsi.index().ptr(elf).node != ni) continue; |
| 5971 | | const old_sym_addr: u64 = switch (elf.symPtr(lsi.index())) { |
| 5972 | | inline else => |sym| switch (elf.targetLoad(&sym.other).visibility) { |
| 5973 | | .HIDDEN, .INTERNAL => { |
| 5974 | | // This is actually a global symbol which got demoted to STB_LOCAL due |
| 5975 | | // to its visibility. It will be handled in the global symbols pass |
| 5976 | | // below; don't touch it now. |
| 5977 | | continue; |
| 5978 | | }, |
| 5979 | | .PROTECTED => unreachable, // not allowed for an STB_LOCAL symbol |
| 5980 | | .DEFAULT => elf.targetLoad(&sym.value), |
| 5981 | | }, |
| 6222 | const visibility: std.elf.STV = switch (elf.symPtr(lsi.index())) { |
| 6223 | inline else => |sym| elf.targetLoad(&sym.other).visibility, |
| 5982 | 6224 | }; |
| 6225 | switch (visibility) { |
| 6226 | .HIDDEN, .INTERNAL => { |
| 6227 | // This is actually a global symbol which got demoted to STB_LOCAL due |
| 6228 | // to its visibility. It will be handled in the global symbols pass |
| 6229 | // below; don't touch it now. |
| 6230 | continue; |
| 6231 | }, |
| 6232 | .PROTECTED => unreachable, // not allowed for an STB_LOCAL symbol |
| 6233 | .DEFAULT => {}, |
| 6234 | } |
| 6235 | const old_sym_addr = Symbol.Id.local(lsi).value(elf); |
| 5983 | 6236 | Symbol.Id.local(lsi).flushMoved( |
| 5984 | 6237 | elf, |
| 5985 | 6238 | old_sym_addr - old_section_addr + new_section_addr, |
| ... | ... | @@ -5991,15 +6244,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 5991 | 6244 | assert(first_name != .empty); |
| 5992 | 6245 | var name = first_name; |
| 5993 | 6246 | while (name != .empty) { |
| 5994 | | const global = elf.globalByName(name).?; |
| 5995 | | const old_sym_addr: u64 = switch (elf.symPtr(global.symtab_index)) { |
| 5996 | | inline else => |sym| elf.targetLoad(&sym.value), |
| 5997 | | }; |
| 6247 | const old_sym_addr = Symbol.Id.global(name).value(elf); |
| 5998 | 6248 | Symbol.Id.global(name).flushMoved( |
| 5999 | 6249 | elf, |
| 6000 | 6250 | old_sym_addr - old_section_addr + new_section_addr, |
| 6001 | 6251 | ); |
| 6002 | | name = global.next_in_node; |
| 6252 | name = elf.globalByName(name).?.next_in_node; |
| 6003 | 6253 | } |
| 6004 | 6254 | } |
| 6005 | 6255 | |
| ... | ... | @@ -6010,6 +6260,19 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 6010 | 6260 | isi.ptrConst(elf).first_got_reloc, |
| 6011 | 6261 | ); |
| 6012 | 6262 | }, |
| 6263 | .copied_global => |global_name| { |
| 6264 | const copied_global = elf.copied_globals.getPtr(global_name) orelse { |
| 6265 | // TODO: this node is orphaned, which is possible because `MappedFile` does not yet |
| 6266 | // support deleting nodes. See logic in `setGlobalSymbolValue`. |
| 6267 | return; |
| 6268 | }; |
| 6269 | assert(copied_global.node == ni); |
| 6270 | |
| 6271 | const new_addr = elf.computeNodeVAddr(ni); |
| 6272 | elf.shndx.rela_dyn.relaSetOffset(elf, copied_global.rela_index, new_addr); |
| 6273 | |
| 6274 | Symbol.Id.global(global_name).flushMoved(elf, new_addr); |
| 6275 | }, |
| 6013 | 6276 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| { |
| 6014 | 6277 | const new_addr = elf.computeNodeVAddr(ni); |
| 6015 | 6278 | Symbol.Id.local(mi.symbol(elf)).flushMoved(elf, new_addr); |
| ... | ... | @@ -6137,7 +6400,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 6137 | 6400 | } |
| 6138 | 6401 | }, |
| 6139 | 6402 | }, |
| 6140 | | .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 6403 | .copied_global, .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 6141 | 6404 | } |
| 6142 | 6405 | } |
| 6143 | 6406 | fn updateDynamicEntry(elf: *Elf, key: u32, new_val: u64) void { |
| ... | ... | @@ -6262,9 +6525,9 @@ fn updateExportsInner( |
| 6262 | 6525 | .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, |
| 6263 | 6526 | }; |
| 6264 | 6527 | while (try elf.idle(pt.tid)) {} |
| 6265 | | const value: u64, const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { |
| 6528 | const value: u64 = Symbol.Id.local(exported_lsi).value(elf); |
| 6529 | const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { |
| 6266 | 6530 | inline else => |exported_sym| .{ |
| 6267 | | elf.targetLoad(&exported_sym.value), |
| 6268 | 6531 | elf.targetLoad(&exported_sym.size), |
| 6269 | 6532 | .fromSection(elf.targetLoad(&exported_sym.shndx)), |
| 6270 | 6533 | }, |
| ... | ... | @@ -6368,6 +6631,7 @@ pub fn printNode( |
| 6368 | 6631 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf), |
| 6369 | 6632 | }); |
| 6370 | 6633 | }, |
| 6634 | .copied_global => |name| try w.print("(copy:{s})", .{name}), |
| 6371 | 6635 | .nav => |nmi| { |
| 6372 | 6636 | const zcu = elf.base.comp.zcu.?; |
| 6373 | 6637 | const ip = &zcu.intern_pool; |