| ... | @@ -244,7 +244,7 @@ section_by_name: std.array_hash_map.Auto(String(.shstrtab), void), | ... | @@ -244,7 +244,7 @@ section_by_name: std.array_hash_map.Auto(String(.shstrtab), void), |
| 244 | changed_symtab_index: std.array_hash_map.Auto(Symbol.Global.Index, void), | 244 | changed_symtab_index: std.array_hash_map.Auto(Symbol.Global.Index, void), |
| 245 | /// Counts how many relocations are currently in `.rela.dyn` which would require a `DT_TEXTREL` | 245 | /// Counts how many relocations are currently in `.rela.dyn` which would require a `DT_TEXTREL` |
| 246 | /// entry in the `.dynamic` section. This allows adding `DT_TEXTREL` to the output `.dynamic` | 246 | /// entry in the `.dynamic` section. This allows adding `DT_TEXTREL` to the output `.dynamic` |
| 247 | /// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`. | 247 | /// section in `flush` only when it is actually necessary. See also `nodeAllowsDynamicReloc`. |
| 248 | textrel_count: u32, | 248 | textrel_count: u32, |
| 249 | | 249 | |
| 250 | dwarf: Dwarf, | 250 | dwarf: Dwarf, |
| ... | @@ -259,6 +259,8 @@ dwarf_decls: std.array_hash_map.Auto(Dwarf.Decl.Index, dwarf_relocs.Decl), | ... | @@ -259,6 +259,8 @@ dwarf_decls: std.array_hash_map.Auto(Dwarf.Decl.Index, dwarf_relocs.Decl), |
| 259 | | 259 | |
| 260 | overflowed_reloc_count: u32, | 260 | overflowed_reloc_count: u32, |
| 261 | misaligned_reloc_count: u32, | 261 | misaligned_reloc_count: u32, |
| | 262 | illegal_dynamic_type_reloc_count: u32, |
| | 263 | illegal_dynamic_section_reloc_count: u32, |
| 262 | | 264 | |
| 263 | const_prog_node: std.Progress.Node, | 265 | const_prog_node: std.Progress.Node, |
| 264 | input_prog_node: std.Progress.Node, | 266 | input_prog_node: std.Progress.Node, |
| ... | @@ -1409,7 +1411,13 @@ const SymbolReloc = struct { | ... | @@ -1409,7 +1411,13 @@ const SymbolReloc = struct { |
| 1409 | /// relocation entry. The entry will be removed if we discover a definition which allows us to | 1411 | /// relocation entry. The entry will be removed if we discover a definition which allows us to |
| 1410 | /// statically resolve the relocation. | 1412 | /// statically resolve the relocation. |
| 1411 | rela_index: Section.RelaIndex.Optional, | 1413 | rela_index: Section.RelaIndex.Optional, |
| 1412 | result: enum(u8) { ok, overflowed, misaligned }, | 1414 | result: enum(u8) { |
| | 1415 | ok, |
| | 1416 | overflowed, |
| | 1417 | misaligned, |
| | 1418 | illegal_dynamic_type, |
| | 1419 | illegal_dynamic_section, |
| | 1420 | }, |
| 1413 | | 1421 | |
| 1414 | /// Determines the section in which this relocation will be placed if it is outstanding. | 1422 | /// Determines the section in which this relocation will be placed if it is outstanding. |
| 1415 | /// | 1423 | /// |
| ... | @@ -1961,6 +1969,10 @@ const SymbolReloc = struct { | ... | @@ -1961,6 +1969,10 @@ const SymbolReloc = struct { |
| 1961 | .ok => {}, | 1969 | .ok => {}, |
| 1962 | .overflowed => elf.overflowed_reloc_count -= 1, | 1970 | .overflowed => elf.overflowed_reloc_count -= 1, |
| 1963 | .misaligned => elf.misaligned_reloc_count -= 1, | 1971 | .misaligned => elf.misaligned_reloc_count -= 1, |
| | 1972 | .illegal_dynamic_type, .illegal_dynamic_section => { |
| | 1973 | // This status won't change until a call to `updateDynamicReloc`. |
| | 1974 | return; |
| | 1975 | }, |
| 1964 | } | 1976 | } |
| 1965 | if (reloc.applyInner(elf)) { | 1977 | if (reloc.applyInner(elf)) { |
| 1966 | @branchHint(.likely); | 1978 | @branchHint(.likely); |
| ... | @@ -2071,6 +2083,8 @@ const SymbolReloc = struct { | ... | @@ -2071,6 +2083,8 @@ const SymbolReloc = struct { |
| 2071 | .ok => {}, | 2083 | .ok => {}, |
| 2072 | .overflowed => elf.overflowed_reloc_count -= 1, | 2084 | .overflowed => elf.overflowed_reloc_count -= 1, |
| 2073 | .misaligned => elf.misaligned_reloc_count -= 1, | 2085 | .misaligned => elf.misaligned_reloc_count -= 1, |
| | 2086 | .illegal_dynamic_type => elf.illegal_dynamic_type_reloc_count -= 1, |
| | 2087 | .illegal_dynamic_section => elf.illegal_dynamic_section_reloc_count -= 1, |
| 2074 | } | 2088 | } |
| 2075 | | 2089 | |
| 2076 | reloc.* = undefined; | 2090 | reloc.* = undefined; |
| ... | @@ -2084,14 +2098,211 @@ const SymbolReloc = struct { | ... | @@ -2084,14 +2098,211 @@ const SymbolReloc = struct { |
| 2084 | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); | 2098 | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); |
| 2085 | switch (elf.ehdrType()) { | 2099 | switch (elf.ehdrType()) { |
| 2086 | .REL => {}, | 2100 | .REL => {}, |
| 2087 | .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node.unwrap().?)) { | 2101 | .EXEC, .DYN => switch (elf.nodeAllowsDynamicReloc(reloc.node.unwrap().?)) { |
| 2088 | .no => unreachable, // there *was* a dynamic relocation! | 2102 | .not_alloc => unreachable, // there *was* a dynamic relocation! |
| 2089 | .yes => {}, | 2103 | .ok => {}, |
| 2090 | .yes_textrel => elf.textrel_count -= 1, | 2104 | .ok_textrel => elf.textrel_count -= 1, |
| 2091 | }, | 2105 | }, |
| 2092 | } | 2106 | } |
| 2093 | reloc.rela_index = .none; | 2107 | reloc.rela_index = .none; |
| 2094 | } | 2108 | } |
| | 2109 | |
| | 2110 | fn updateDynamicReloc(reloc: *SymbolReloc, elf: *Elf) Error!void { |
| | 2111 | assert(elf.ehdrType() != .REL); |
| | 2112 | const reloc_node = reloc.node.unwrap().?; // deleted |
| | 2113 | |
| | 2114 | // Delete any current output relocation or error. |
| | 2115 | switch (reloc.result) { |
| | 2116 | .ok, .overflowed, .misaligned => { |
| | 2117 | reloc.deleteOutputRel(elf); |
| | 2118 | }, |
| | 2119 | .illegal_dynamic_type => { |
| | 2120 | elf.illegal_dynamic_type_reloc_count -= 1; |
| | 2121 | reloc.result = .ok; |
| | 2122 | }, |
| | 2123 | .illegal_dynamic_section => { |
| | 2124 | elf.illegal_dynamic_section_reloc_count -= 1; |
| | 2125 | reloc.result = .ok; |
| | 2126 | }, |
| | 2127 | } |
| | 2128 | |
| | 2129 | assert(reloc.rela_index == .none); |
| | 2130 | |
| | 2131 | const symbol_class = elf.classifySymbolValue(reloc.target); |
| | 2132 | |
| | 2133 | switch (reloc.target.unwrap()) { |
| | 2134 | .local => {}, |
| | 2135 | .global => |gsi| switch (symbol_class) { |
| | 2136 | .static => gsi.ptr(elf).status.any_static_target_relocs = true, |
| | 2137 | .static_relative => gsi.ptr(elf).status.any_static_relative_target_relocs = true, |
| | 2138 | .dynamic => gsi.ptr(elf).status.any_dynamic_target_relocs = true, |
| | 2139 | }, |
| | 2140 | } |
| | 2141 | |
| | 2142 | const want_dynamic_reloc: enum { |
| | 2143 | /// `reloc` cannot be statically resolved, but is not an allowed dynamic relocation. |
| | 2144 | illegal, |
| | 2145 | relative, |
| | 2146 | abs_addr, |
| | 2147 | dtp_off, |
| | 2148 | tp_off, |
| | 2149 | size32, |
| | 2150 | size64, |
| | 2151 | } = switch (symbol_class) { |
| | 2152 | .static => return, |
| | 2153 | |
| | 2154 | .static_relative => switch (reloc.type.target) { |
| | 2155 | // We need a runtime relocation if the relocation depends on our load address, which |
| | 2156 | // is the case iff the relocation resolves to the absolute value of a symbol. Relocs |
| | 2157 | // which are PC-relative, or which resolve to something other than a symbol address |
| | 2158 | // (e.g. a symbol's size), are fine. |
| | 2159 | |
| | 2160 | .pltrel, |
| | 2161 | .rel, |
| | 2162 | .size, |
| | 2163 | .dtpoff, |
| | 2164 | .tpoff, |
| | 2165 | => return, |
| | 2166 | |
| | 2167 | .abs, .pltabs => switch (reloc.type.action.simple.dest.isAddr(elf)) { |
| | 2168 | true => .relative, |
| | 2169 | false => .illegal, |
| | 2170 | }, |
| | 2171 | |
| | 2172 | .special => switch (reloc.type.action.special) { |
| | 2173 | .larch_pcala_hi20, |
| | 2174 | .larch_pcala64_lo20, |
| | 2175 | .larch_pcala64_hi12, |
| | 2176 | .larch_b21, |
| | 2177 | .larch_b26, |
| | 2178 | .larch_call36, |
| | 2179 | .sparc_wdisp10, |
| | 2180 | .sparc_wdisp16, |
| | 2181 | .sparc_le_hix22, |
| | 2182 | => return, |
| | 2183 | |
| | 2184 | .sparc_olo10, |
| | 2185 | .sparc_hix22, |
| | 2186 | => .illegal, |
| | 2187 | }, |
| | 2188 | }, |
| | 2189 | |
| | 2190 | .dynamic => switch (reloc.type.target) { |
| | 2191 | // PLT relocations targeting dynamic symbols actually target that symbol's PLT |
| | 2192 | // entry, so we should emit an `R_*_RELATIVE` relocation instead. |
| | 2193 | .pltabs => switch (reloc.type.action.simple.dest.isAddr(elf)) { |
| | 2194 | true => .relative, |
| | 2195 | false => .illegal, |
| | 2196 | }, |
| | 2197 | // ...although PC-relative PLT relocations don't even need that that! |
| | 2198 | .pltrel => return, |
| | 2199 | // PC-relative relocations are not valid dynamic relocations. |
| | 2200 | .rel => .illegal, |
| | 2201 | // On the few targets supporting size relocations, they are valid at runtime. |
| | 2202 | .size => switch (reloc.type.action.simple.dest) { |
| | 2203 | .@"32" => .size32, |
| | 2204 | .@"64" => .size64, |
| | 2205 | else => .illegal, |
| | 2206 | }, |
| | 2207 | // Absolute addresses and TLS offsets can be lowered at runtime provided they |
| | 2208 | // are address-sized. |
| | 2209 | .dtpoff => switch (reloc.type.action.simple.dest.isAddr(elf)) { |
| | 2210 | true => .dtp_off, |
| | 2211 | false => .illegal, |
| | 2212 | }, |
| | 2213 | .tpoff => switch (reloc.type.action.simple.dest.isAddr(elf)) { |
| | 2214 | true => .tp_off, |
| | 2215 | false => .illegal, |
| | 2216 | }, |
| | 2217 | .abs => switch (reloc.type.action.simple.dest.isAddr(elf)) { |
| | 2218 | true => .abs_addr, |
| | 2219 | false => .illegal, |
| | 2220 | }, |
| | 2221 | |
| | 2222 | .special => switch (reloc.type.action.special) { |
| | 2223 | .larch_b21, |
| | 2224 | .larch_b26, |
| | 2225 | .larch_call36, |
| | 2226 | .sparc_wdisp10, |
| | 2227 | .sparc_wdisp16, |
| | 2228 | => return, |
| | 2229 | |
| | 2230 | .larch_pcala_hi20, |
| | 2231 | .larch_pcala64_lo20, |
| | 2232 | .larch_pcala64_hi12, |
| | 2233 | .sparc_olo10, |
| | 2234 | .sparc_hix22, |
| | 2235 | .sparc_le_hix22, |
| | 2236 | => .illegal, |
| | 2237 | }, |
| | 2238 | }, |
| | 2239 | }; |
| | 2240 | |
| | 2241 | const is_textrel: bool = switch (elf.nodeAllowsDynamicReloc(reloc_node)) { |
| | 2242 | .not_alloc => { |
| | 2243 | // The section containing the relocation is not loaded into memory. These sections |
| | 2244 | // have slightly different rules. In other ELF linkers, they basically just let any |
| | 2245 | // relocation through at any time---they will bind to a local symbol definition if |
| | 2246 | // it exists, or just to 0 otherwise. I think that's a little scary though, so until |
| | 2247 | // I come across a compelling reason for us to mimic that behaviour, let's be more |
| | 2248 | // conservative and only allow what seems necessary: |
| | 2249 | const allow: bool = switch (want_dynamic_reloc) { |
| | 2250 | // Relocations which target the value/[d]tpoff of a symbol with a local |
| | 2251 | // definition, and which write their result to a full address-sized word, have |
| | 2252 | // clear use cases (e.g. DWARF uses these), so let them through. |
| | 2253 | .relative, |
| | 2254 | .abs_addr, |
| | 2255 | .dtp_off, |
| | 2256 | .tp_off, |
| | 2257 | => switch (reloc.target.unwrap()) { |
| | 2258 | .local => true, |
| | 2259 | .global => |gsi| gsi.resolveAlias(elf).defined(elf), |
| | 2260 | }, |
| | 2261 | |
| | 2262 | // Everything else I'm going to disallow for now. Remember that we're already in |
| | 2263 | // the dynamic case here, so this isn't disallowing (e.g.) all size relocations |
| | 2264 | // in these sections, just size relocations *targeting dynamic symbols*! |
| | 2265 | .size32, .size64, .illegal => false, |
| | 2266 | }; |
| | 2267 | if (!allow) { |
| | 2268 | // ...but in this case we actually do need to trigger an error. |
| | 2269 | reloc.result = .illegal_dynamic_section; |
| | 2270 | elf.illegal_dynamic_section_reloc_count += 1; |
| | 2271 | } |
| | 2272 | return; |
| | 2273 | }, |
| | 2274 | .ok => false, |
| | 2275 | .ok_textrel => true, |
| | 2276 | }; |
| | 2277 | |
| | 2278 | const rel_type: MachineRelocType = rel: switch (want_dynamic_reloc) { |
| | 2279 | .illegal => { |
| | 2280 | reloc.result = .illegal_dynamic_type; |
| | 2281 | elf.illegal_dynamic_type_reloc_count += 1; |
| | 2282 | return; |
| | 2283 | }, |
| | 2284 | .relative => .relative(elf), |
| | 2285 | .abs_addr => .absAddr(elf), |
| | 2286 | .dtp_off => .dtpOff(elf), |
| | 2287 | .tp_off => .tpOff(elf), |
| | 2288 | .size32 => MachineRelocType.size32(elf) orelse continue :rel .illegal, |
| | 2289 | .size64 => MachineRelocType.size64(elf) orelse continue :rel .illegal, |
| | 2290 | }; |
| | 2291 | const target_dynsym: u32 = switch (want_dynamic_reloc) { |
| | 2292 | .illegal => unreachable, // handled above |
| | 2293 | .relative => 0, |
| | 2294 | else => reloc.target.unwrap().global.dynsymIndex(elf).?, |
| | 2295 | }; |
| | 2296 | |
| | 2297 | try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, 1); |
| | 2298 | reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ |
| | 2299 | .type = rel_type, |
| | 2300 | .offset = elf.getNodeVAddr(reloc_node) + reloc.offset, |
| | 2301 | .raw_sym_index = target_dynsym, |
| | 2302 | .addend = reloc.addend.normal, |
| | 2303 | }).toOptional(); |
| | 2304 | if (is_textrel) elf.textrel_count += 1; |
| | 2305 | } |
| 2095 | }; | 2306 | }; |
| 2096 | | 2307 | |
| 2097 | /// A relocation targeting an arbitrary node (within a section) with a fixed addend. | 2308 | /// A relocation targeting an arbitrary node (within a section) with a fixed addend. |
| ... | @@ -2909,9 +3120,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{ | ... | @@ -2909,9 +3120,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{ |
| 2909 | } | 3120 | } |
| 2910 | } | 3121 | } |
| 2911 | | 3122 | |
| 2912 | if (elf.mergeGlobalSymbolVisibility(gsi, opts.visibility)) { | 3123 | elf.mergeGlobalSymbolVisibility(gsi, opts.visibility); |
| 2913 | force_apply_relocs = true; | | |
| 2914 | } | | |
| 2915 | | 3124 | |
| 2916 | // There's already a symbol with this name, we just need to potentially set its value, and | 3125 | // There's already a symbol with this name, we just need to potentially set its value, and |
| 2917 | // to update its bind and visibility. | 3126 | // to update its bind and visibility. |
| ... | @@ -3167,14 +3376,23 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel | ... | @@ -3167,14 +3376,23 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel |
| 3167 | }, | 3376 | }, |
| 3168 | }; | 3377 | }; |
| 3169 | | 3378 | |
| 3170 | const omit_dynsym: bool = omit: { | 3379 | const have_dynsym: bool = switch (elf.shndx.dynsym) { |
| 3171 | if (elf.shndx.dynsym == .UNDEF) break :omit true; | 3380 | .UNDEF => false, |
| 3172 | break :omit switch (visibility) { | 3381 | else => switch (visibility) { |
| 3173 | .HIDDEN, .INTERNAL => true, | 3382 | .HIDDEN, .INTERNAL => false, |
| 3174 | .DEFAULT, .PROTECTED => false, | 3383 | // An undefined protected dynamic symbol would be pointless, because protected symbols |
| 3175 | }; | 3384 | // don't bind to external definitions; so only add to dynsym if we have a definition. |
| | 3385 | .PROTECTED => gsi.defined(elf), |
| | 3386 | // Executables conventionally do not put symbols in their dynamic symbol table unless a |
| | 3387 | // definition is seen, while dynamic libraries just chuck 'em all in. |
| | 3388 | .DEFAULT => switch (elf.base.comp.config.output_mode) { |
| | 3389 | .Exe => gsi.defined(elf) or maybe_dso_global != null, |
| | 3390 | .Lib => true, |
| | 3391 | .Obj => unreachable, // we have a dynamic symbol table |
| | 3392 | }, |
| | 3393 | }, |
| 3176 | }; | 3394 | }; |
| 3177 | if (omit_dynsym) { | 3395 | if (!have_dynsym) { |
| 3178 | if (try elf.deleteOwnedDynsym(gsi)) { | 3396 | if (try elf.deleteOwnedDynsym(gsi)) { |
| 3179 | apply_relocs = true; | 3397 | apply_relocs = true; |
| 3180 | } | 3398 | } |
| ... | @@ -3201,9 +3419,14 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel | ... | @@ -3201,9 +3419,14 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel |
| 3201 | if (elf.ehdrType() != .REL) { | 3419 | if (elf.ehdrType() != .REL) { |
| 3202 | assert(elf.classifySymbolValue(.global(gsi)) != .dynamic); | 3420 | assert(elf.classifySymbolValue(.global(gsi)) != .dynamic); |
| 3203 | } | 3421 | } |
| 3204 | gsi.deleteDynamicTargetRelocs(elf); | 3422 | |
| | 3423 | if (try gsi.updateDynamicTargetRelocs(elf)) { |
| | 3424 | apply_relocs = true; |
| | 3425 | } |
| 3205 | if (maybe_alias_gsi) |alias_gsi| { | 3426 | if (maybe_alias_gsi) |alias_gsi| { |
| 3206 | alias_gsi.deleteDynamicTargetRelocs(elf); | 3427 | if (try alias_gsi.updateDynamicTargetRelocs(elf)) { |
| | 3428 | apply_relocs = true; |
| | 3429 | } |
| 3207 | } | 3430 | } |
| 3208 | | 3431 | |
| 3209 | if (apply_relocs) { | 3432 | if (apply_relocs) { |
| ... | @@ -3462,10 +3685,12 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel | ... | @@ -3462,10 +3685,12 @@ fn updateGlobalDynamic(elf: *Elf, orig_gsi: Symbol.Global.Index, force_apply_rel |
| 3462 | _ = elf.unknown_globals.swapRemove(gsi); | 3685 | _ = elf.unknown_globals.swapRemove(gsi); |
| 3463 | } | 3686 | } |
| 3464 | | 3687 | |
| 3465 | if (elf.classifySymbolValue(.global(gsi)) != .dynamic) { | 3688 | if (try gsi.updateDynamicTargetRelocs(elf)) { |
| 3466 | gsi.deleteDynamicTargetRelocs(elf); | 3689 | apply_relocs = true; |
| 3467 | if (maybe_alias_gsi) |alias_gsi| { | 3690 | } |
| 3468 | alias_gsi.deleteDynamicTargetRelocs(elf); | 3691 | if (maybe_alias_gsi) |alias_gsi| { |
| | 3692 | if (try alias_gsi.updateDynamicTargetRelocs(elf)) { |
| | 3693 | apply_relocs = true; |
| 3469 | } | 3694 | } |
| 3470 | } | 3695 | } |
| 3471 | | 3696 | |
| ... | @@ -3588,15 +3813,12 @@ fn setGlobalSymbolBind( | ... | @@ -3588,15 +3813,12 @@ fn setGlobalSymbolBind( |
| 3588 | /// undefined---their visibility values are combined to determine the resulting visibility. | 3813 | /// undefined---their visibility values are combined to determine the resulting visibility. |
| 3589 | /// | 3814 | /// |
| 3590 | /// Every call to this function *must* be followed by a call to `updateGlobalDynamic` since changes | 3815 | /// Every call to this function *must* be followed by a call to `updateGlobalDynamic` since changes |
| 3591 | /// to symbol visibility can affect the dynamic symbol table entry. If this function returns `true`, | 3816 | /// to symbol visibility can affect the dynamic symbol table entry. |
| 3592 | /// then that `updateGlobalDynamic` call must have the `force_apply_relocs` argument set to `true`, | | |
| 3593 | /// because this symbol's classification has changed (it is no longer a dynamic symbol) so | | |
| 3594 | /// relocations targeting the symbol must be re-applied. | | |
| 3595 | fn mergeGlobalSymbolVisibility( | 3817 | fn mergeGlobalSymbolVisibility( |
| 3596 | elf: *Elf, | 3818 | elf: *Elf, |
| 3597 | gsi: Symbol.Global.Index, | 3819 | gsi: Symbol.Global.Index, |
| 3598 | other_visibility: std.elf.STV, | 3820 | other_visibility: std.elf.STV, |
| 3599 | ) bool { | 3821 | ) void { |
| 3600 | const old_visibility: std.elf.STV = switch (elf.symPtr(gsi.ptr(elf).symtab_index)) { | 3822 | const old_visibility: std.elf.STV = switch (elf.symPtr(gsi.ptr(elf).symtab_index)) { |
| 3601 | inline else => |sym| elf.targetLoad(&sym.other).visibility, | 3823 | inline else => |sym| elf.targetLoad(&sym.other).visibility, |
| 3602 | }; | 3824 | }; |
| ... | @@ -3628,13 +3850,13 @@ fn mergeGlobalSymbolVisibility( | ... | @@ -3628,13 +3850,13 @@ fn mergeGlobalSymbolVisibility( |
| 3628 | ), | 3850 | ), |
| 3629 | } | 3851 | } |
| 3630 | | 3852 | |
| 3631 | if (elf.ehdrType() == .REL) { | 3853 | if (elf.ehdrType() == .REL) return; |
| 3632 | return false; | | |
| 3633 | } | | |
| 3634 | | 3854 | |
| 3635 | // We also need to deal with a concept I call "symbol demotion". If a symbol is `STV_HIDDEN` or | 3855 | // We also need to deal with a concept I call "symbol demotion". If a symbol is `STV_HIDDEN` or |
| 3636 | // `STV_INTERNAL`, and we're emitting an ELF module (executable or shared object, as opposed to | 3856 | // `STV_INTERNAL`, and we're emitting an ELF module (executable or shared object, as opposed to |
| 3637 | // a relocatable), then the symbol should be "demoted" to binding `STB_LOCAL` in the output. | 3857 | // a relocatable), then the symbol should be "demoted" to binding `STB_LOCAL` in the output. |
| | 3858 | // TODO: after the latest batch of refactors, I'm unsure if this logic should be here anymore. I |
| | 3859 | // think it should probably live in `updateGlobalDynamic` instead. |
| 3638 | const old_demoted: bool = switch (old_visibility) { | 3860 | const old_demoted: bool = switch (old_visibility) { |
| 3639 | .INTERNAL, .HIDDEN => true, | 3861 | .INTERNAL, .HIDDEN => true, |
| 3640 | .DEFAULT, .PROTECTED => false, | 3862 | .DEFAULT, .PROTECTED => false, |
| ... | @@ -3652,16 +3874,6 @@ fn mergeGlobalSymbolVisibility( | ... | @@ -3652,16 +3874,6 @@ fn mergeGlobalSymbolVisibility( |
| 3652 | } | 3874 | } |
| 3653 | elf.moveDemotedGlobal(gsi); | 3875 | elf.moveDemotedGlobal(gsi); |
| 3654 | } | 3876 | } |
| 3655 | | | |
| 3656 | const old_protected: bool = switch (old_visibility) { | | |
| 3657 | .PROTECTED, .INTERNAL, .HIDDEN => true, | | |
| 3658 | .DEFAULT => false, | | |
| 3659 | }; | | |
| 3660 | const new_protected: bool = switch (new_visibility) { | | |
| 3661 | .PROTECTED, .INTERNAL, .HIDDEN => true, | | |
| 3662 | .DEFAULT => false, | | |
| 3663 | }; | | |
| 3664 | return old_protected != new_protected; | | |
| 3665 | } | 3877 | } |
| 3666 | /// If a symbol which was STB_GLOBAL/STB_WEAK becomes STB_LOCAL (see `mergeGlobalSymbolVisibility`), | 3878 | /// If a symbol which was STB_GLOBAL/STB_WEAK becomes STB_LOCAL (see `mergeGlobalSymbolVisibility`), |
| 3667 | /// the symbol must be moved from the "globals" part of the symtab to the "locals" part, because ELF | 3879 | /// the symbol must be moved from the "globals" part of the symtab to the "locals" part, because ELF |
| ... | @@ -4038,85 +4250,52 @@ const Symbol = struct { | ... | @@ -4038,85 +4250,52 @@ const Symbol = struct { |
| 4038 | return null; | 4250 | return null; |
| 4039 | } | 4251 | } |
| 4040 | | 4252 | |
| 4041 | /// Scans through all relocations targeting `gsi`, deletes their dynamic relocation | 4253 | /// Updates the dynamic relocations associated with relocations targeting `gsi`, adding |
| 4042 | /// entries, and adds `R_*_RELATIVE` relocation entries as needed. | 4254 | /// or removing them as needed based on the current classification of `gsi`. |
| 4043 | /// | 4255 | /// |
| 4044 | /// Asserts we are creating a DSO. | 4256 | /// Returns `true` if any relocations were updated, in which case relocations targeting |
| 4045 | fn deleteDynamicTargetRelocs(gsi: Symbol.Global.Index, elf: *Elf) void { | 4257 | /// `gsi` must be re-applied by the caller. |
| 4046 | if (elf.shndx.dynamic == .UNDEF) return; | 4258 | fn updateDynamicTargetRelocs(gsi: Symbol.Global.Index, elf: *Elf) Error!bool { |
| | 4259 | if (elf.shndx.dynamic == .UNDEF) return false; |
| 4047 | const sym_id: Symbol.Id = .global(gsi); | 4260 | const sym_id: Symbol.Id = .global(gsi); |
| | 4261 | |
| 4048 | switch (elf.classifySymbolValue(sym_id)) { | 4262 | switch (elf.classifySymbolValue(sym_id)) { |
| 4049 | .static => { | 4263 | .static => { |
| 4050 | if (!gsi.ptr(elf).status.any_dynamic_target_relocs and | 4264 | if (!gsi.ptr(elf).status.any_dynamic_target_relocs and |
| 4051 | !gsi.ptr(elf).status.any_static_relative_target_relocs) | 4265 | !gsi.ptr(elf).status.any_static_relative_target_relocs) |
| 4052 | { | 4266 | { |
| 4053 | return; | 4267 | return false; |
| 4054 | } | 4268 | } |
| 4055 | gsi.ptr(elf).status.any_dynamic_target_relocs = false; | | |
| 4056 | gsi.ptr(elf).status.any_static_relative_target_relocs = false; | | |
| 4057 | gsi.ptr(elf).status.any_static_target_relocs = true; | | |
| 4058 | }, | 4269 | }, |
| 4059 | .static_relative => { | 4270 | .static_relative => { |
| 4060 | if (!gsi.ptr(elf).status.any_dynamic_target_relocs and | 4271 | if (!gsi.ptr(elf).status.any_dynamic_target_relocs and |
| 4061 | !gsi.ptr(elf).status.any_static_target_relocs) | 4272 | !gsi.ptr(elf).status.any_static_target_relocs) |
| 4062 | { | 4273 | { |
| 4063 | return; | 4274 | return false; |
| | 4275 | } |
| | 4276 | }, |
| | 4277 | .dynamic => { |
| | 4278 | if (!gsi.ptr(elf).status.any_static_target_relocs and |
| | 4279 | !gsi.ptr(elf).status.any_static_relative_target_relocs) |
| | 4280 | { |
| | 4281 | return false; |
| 4064 | } | 4282 | } |
| 4065 | gsi.ptr(elf).status.any_dynamic_target_relocs = false; | | |
| 4066 | gsi.ptr(elf).status.any_static_target_relocs = false; | | |
| 4067 | gsi.ptr(elf).status.any_static_relative_target_relocs = true; | | |
| 4068 | }, | 4283 | }, |
| 4069 | // TODO: this function needs to support a symbol becoming dynamic which wasn't | | |
| 4070 | // previously dynamic (and when it does, the function should be renamed to | | |
| 4071 | // `updateTargetOutputRelocs`). But for now, this isn't supported. | | |
| 4072 | .dynamic => unreachable, | | |
| 4073 | } | 4284 | } |
| | 4285 | |
| | 4286 | gsi.ptr(elf).status.any_static_target_relocs = false; |
| | 4287 | gsi.ptr(elf).status.any_static_relative_target_relocs = false; |
| | 4288 | gsi.ptr(elf).status.any_dynamic_target_relocs = false; |
| | 4289 | |
| 4074 | var ri = sym_id.index(elf).ptr(elf).first_target_reloc; | 4290 | var ri = sym_id.index(elf).ptr(elf).first_target_reloc; |
| 4075 | while (ri != .none) { | 4291 | while (ri != .none) { |
| 4076 | const reloc = ri.get(elf); | 4292 | const reloc = ri.get(elf); |
| 4077 | assert(reloc.target == sym_id); | 4293 | assert(reloc.target == sym_id); |
| 4078 | reloc.deleteOutputRel(elf); | 4294 | try reloc.updateDynamicReloc(elf); |
| 4079 | ri = reloc.next; | 4295 | ri = reloc.next; |
| 4080 | } | 4296 | } |
| 4081 | switch (elf.classifySymbolValue(sym_id)) { | 4297 | |
| 4082 | .static => return, | 4298 | return true; |
| 4083 | .static_relative => {}, | | |
| 4084 | .dynamic => unreachable, | | |
| 4085 | } | | |
| 4086 | // We removed the symbol relocations, now add R_*_RELATIVE relocations where needed. | | |
| 4087 | ri = sym_id.index(elf).ptr(elf).first_target_reloc; | | |
| 4088 | while (ri != .none) { | | |
| 4089 | const reloc = ri.get(elf); | | |
| 4090 | ri = reloc.next; | | |
| 4091 | assert(reloc.target == sym_id); | | |
| 4092 | switch (reloc.type.target) { | | |
| 4093 | // Only relocations which resolve to absolute addresses require runtime | | |
| 4094 | // `R_*_RELATIVE` relocations. | | |
| 4095 | .special, | | |
| 4096 | .pltrel, | | |
| 4097 | .rel, | | |
| 4098 | .dtpoff, | | |
| 4099 | .tpoff, | | |
| 4100 | .size, | | |
| 4101 | => continue, | | |
| 4102 | | | |
| 4103 | .abs, .pltabs => {}, | | |
| 4104 | } | | |
| 4105 | if (!reloc.type.action.simple.dest.isAddr(elf)) continue; | | |
| 4106 | const node = reloc.node.unwrap().?; | | |
| 4107 | switch (elf.nodeWantsDsoRelocation(node)) { | | |
| 4108 | .no => continue, | | |
| 4109 | .yes_textrel => elf.textrel_count += 1, | | |
| 4110 | .yes => {}, | | |
| 4111 | } | | |
| 4112 | // There is capacity for a relocation because we just deleted one earlier. | | |
| 4113 | reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ | | |
| 4114 | .type = .relative(elf), | | |
| 4115 | .offset = elf.getNodeVAddr(node) + reloc.offset, | | |
| 4116 | .raw_sym_index = 0, | | |
| 4117 | .addend = 0, | | |
| 4118 | }).toOptional(); | | |
| 4119 | } | | |
| 4120 | } | 4299 | } |
| 4121 | | 4300 | |
| 4122 | const Optional = enum(u32) { | 4301 | const Optional = enum(u32) { |
| ... | @@ -4370,61 +4549,53 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum { | ... | @@ -4370,61 +4549,53 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum { |
| 4370 | .EXEC => false, | 4549 | .EXEC => false, |
| 4371 | }; | 4550 | }; |
| 4372 | | 4551 | |
| 4373 | if (elf.shndx.dynamic == .UNDEF) { | | |
| 4374 | // This is a static non-PIE executable---every symbol has a statically known value. | | |
| 4375 | return .static; | | |
| 4376 | } | | |
| 4377 | | | |
| 4378 | const resolved_sym = sym.resolveAlias(elf); | 4552 | const resolved_sym = sym.resolveAlias(elf); |
| 4379 | | 4553 | |
| 4380 | const shndx: Section.Index, const visibility: std.elf.STV = switch (elf.symPtr(resolved_sym.index(elf))) { | 4554 | const symtab_shndx: Section.Index, const visibility: std.elf.STV = switch (elf.symPtr(resolved_sym.index(elf))) { |
| 4381 | inline else => |sym_ptr| .{ | 4555 | inline else => |sym_ptr| .{ |
| 4382 | .fromSection(elf.targetLoad(&sym_ptr.shndx)), | 4556 | .fromSection(elf.targetLoad(&sym_ptr.shndx)), |
| 4383 | elf.targetLoad(&sym_ptr.other).visibility, | 4557 | elf.targetLoad(&sym_ptr.other).visibility, |
| 4384 | }, | 4558 | }, |
| 4385 | }; | 4559 | }; |
| 4386 | | 4560 | |
| 4387 | switch (resolved_sym.unwrap()) { | 4561 | const shndx: Section.Index = switch (resolved_sym.unwrap()) { |
| 4388 | .local => { | 4562 | .local => shndx: { |
| 4389 | assert(shndx != .UNDEF); | 4563 | assert(symtab_shndx != .UNDEF); |
| 4390 | assert(visibility == .DEFAULT); | 4564 | assert(visibility == .DEFAULT); |
| | 4565 | break :shndx symtab_shndx; |
| 4391 | }, | 4566 | }, |
| 4392 | .global => |gsi| if (visibility == .DEFAULT and comp.config.output_mode != .Exe) { | 4567 | .global => |gsi| shndx: { |
| 4393 | // An unprotected symbol in a DSO which is not an executable is subject to runtime | 4568 | const shndx: Section.Index = switch (symtab_shndx) { |
| 4394 | // preemption, so a dynamic relocation is required for it even if we have a definition. | 4569 | .UNDEF => if (elf.copied_globals.contains(gsi)) .data else .UNDEF, |
| 4395 | return .dynamic; | 4570 | else => |shndx| shndx, |
| 4396 | } else if (elf.copied_globals.contains(gsi)) { | 4571 | }; |
| 4397 | // This becomes a locally-defined symbol in `.data`. | | |
| 4398 | return if (runtime_load_addr) .static_relative else .static; | | |
| 4399 | }, | | |
| 4400 | } | | |
| 4401 | | 4572 | |
| 4402 | return switch (shndx) { | 4573 | // Check for dynamic symbols before falling into the static path. |
| 4403 | .UNDEF => switch (visibility) { | 4574 | if (gsi.dynsymIndex(elf) != null and visibility == .DEFAULT) { |
| 4404 | .DEFAULT => if (comp.config.link_mode == .static and comp.config.output_mode == .Exe) { | 4575 | if (shndx == .UNDEF) { |
| 4405 | assert(comp.config.pie); // non-PIE static exe should not have a `.dynamic` section | 4576 | // There is no local definition of this symbol. |
| 4406 | // This is a static PIE---we'll see a definition at some point, so there'd be no | 4577 | return .dynamic; |
| 4407 | // point in adding an invalid dynamic relocation (the only valid dynamic relation | 4578 | } else if (comp.config.output_mode != .Exe) { |
| 4408 | // type in a static PIE is `R_*_RELATIVE`). | 4579 | // There is a local definition, but it is preemptible at runtime. |
| 4409 | return .static; | 4580 | return .dynamic; |
| 4410 | } else .dynamic, // external symbol | 4581 | } |
| | 4582 | } |
| 4411 | | 4583 | |
| 4412 | // If the symbol *cannot* be external, then there's no point making a dynamic relocation | 4584 | break :shndx shndx; |
| 4413 | // now---if linking succeeds we won't need anything more than perhaps an `R_*_RELATIVE`. | | |
| 4414 | .INTERNAL, .HIDDEN, .PROTECTED => .static, | | |
| 4415 | }, | 4585 | }, |
| | 4586 | }; |
| 4416 | | 4587 | |
| 4417 | .ABS => .static, | 4588 | if (runtime_load_addr and |
| | 4589 | shndx != .UNDEF and |
| | 4590 | shndx != .ABS and |
| | 4591 | shndx.flags(elf).ALLOC and |
| | 4592 | !shndx.flags(elf).TLS) |
| | 4593 | { |
| | 4594 | // This symbol's value is a virtual address relative to a runtime-known load address. |
| | 4595 | return .static_relative; |
| | 4596 | } |
| 4418 | | 4597 | |
| 4419 | else => if (runtime_load_addr and | 4598 | return .static; |
| 4420 | shndx.flags(elf).ALLOC and | | |
| 4421 | !shndx.flags(elf).TLS) | | |
| 4422 | { | | |
| 4423 | return .static_relative; | | |
| 4424 | } else { | | |
| 4425 | return .static; | | |
| 4426 | }, | | |
| 4427 | }; | | |
| 4428 | } | 4599 | } |
| 4429 | | 4600 | |
| 4430 | pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { | 4601 | pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { |
| ... | @@ -4994,6 +5165,8 @@ fn create( | ... | @@ -4994,6 +5165,8 @@ fn create( |
| 4994 | | 5165 | |
| 4995 | .overflowed_reloc_count = 0, | 5166 | .overflowed_reloc_count = 0, |
| 4996 | .misaligned_reloc_count = 0, | 5167 | .misaligned_reloc_count = 0, |
| | 5168 | .illegal_dynamic_type_reloc_count = 0, |
| | 5169 | .illegal_dynamic_section_reloc_count = 0, |
| 4997 | | 5170 | |
| 4998 | .const_prog_node = .none, | 5171 | .const_prog_node = .none, |
| 4999 | .input_prog_node = .none, | 5172 | .input_prog_node = .none, |
| ... | @@ -9701,18 +9874,21 @@ fn addSymbolRelocAssumeCapacityInner( | ... | @@ -9701,18 +9874,21 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9701 | ) Error!void { | 9874 | ) Error!void { |
| 9702 | assert(elf.ehdrType() != .REL); | 9875 | assert(elf.ehdrType() != .REL); |
| 9703 | | 9876 | |
| 9704 | const rela_index: Section.RelaIndex.Optional = r: { | 9877 | request_static_target: { |
| 9705 | if (elf.shndx.dynamic == .UNDEF) break :r .none; | 9878 | if (elf.shndx.dynamic == .UNDEF) break :request_static_target; |
| 9706 | | 9879 | const gsi: Symbol.Global.Index = switch (target.unwrap()) { |
| 9707 | // If we emit a runtime relocation entry, its `offset` is a virtual address, so we need to | 9880 | .local => break :request_static_target, |
| 9708 | // determine the vaddr of `node`. | 9881 | .global => |gsi| gsi, |
| 9709 | const node_vaddr = elf.getNodeVAddr(node); | 9882 | }; |
| 9710 | | 9883 | // The target symbol may be dynamic, in which case its value cannot be resolved statically. |
| 9711 | // If this is `true`, we will try to create a copy relocation for the target symbol if it is | 9884 | // However, there are strategies (such as copy relocations) the linker can employ which can |
| 9712 | // not locally defined. If the relocation value is always computed from the target symbol's | 9885 | // effectively convert dynamic symbols into static symbols. If statically resolving this |
| 9713 | // value (even for an external target symbol), and if the target symbol might be of type | 9886 | // relocation would require knowing the symbol value, we can set a flag so that those |
| 9714 | // STT_OBJECT, this should probably be `true`. | 9887 | // strategies are used when possible to make this relocation statically resolvable. |
| 9715 | const try_copy_reloc: bool = switch (@"type".target) { | 9888 | // |
| | 9889 | // (This `switch` should return `false` for TLS relocations, because we can't do anything |
| | 9890 | // about TLS symbols being dynamic.) |
| | 9891 | const want_static_value: bool = switch (@"type".target) { |
| 9716 | .rel, .abs => true, | 9892 | .rel, .abs => true, |
| 9717 | | 9893 | |
| 9718 | .pltrel, | 9894 | .pltrel, |
| ... | @@ -9741,92 +9917,13 @@ fn addSymbolRelocAssumeCapacityInner( | ... | @@ -9741,92 +9917,13 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9741 | => false, | 9917 | => false, |
| 9742 | }, | 9918 | }, |
| 9743 | }; | 9919 | }; |
| 9744 | if (try_copy_reloc) switch (target.unwrap()) { | 9920 | if (!want_static_value) break :request_static_target; |
| 9745 | .local => {}, | | |
| 9746 | .global => |gsi| if (!gsi.ptr(elf).status.want_static_value) { | | |
| 9747 | gsi.ptr(elf).status.want_static_value = true; | | |
| 9748 | try elf.updateGlobalDynamic(gsi, false); | | |
| 9749 | }, | | |
| 9750 | }; | | |
| 9751 | | | |
| 9752 | classify: switch (elf.classifySymbolValue(target)) { | | |
| 9753 | .static => { | | |
| 9754 | switch (target.unwrap()) { | | |
| 9755 | .local => {}, | | |
| 9756 | .global => |gsi| gsi.ptr(elf).status.any_static_target_relocs = true, | | |
| 9757 | } | | |
| 9758 | break :r .none; | | |
| 9759 | }, | | |
| 9760 | .static_relative => { | | |
| 9761 | switch (target.unwrap()) { | | |
| 9762 | .local => {}, | | |
| 9763 | .global => |gsi| gsi.ptr(elf).status.any_static_relative_target_relocs = true, | | |
| 9764 | } | | |
| 9765 | switch (@"type".target) { | | |
| 9766 | // Only relocations which resolve to absolute addresses require runtime | | |
| 9767 | // `R_*_RELATIVE` relocations. | | |
| 9768 | .special, | | |
| 9769 | .pltrel, | | |
| 9770 | .rel, | | |
| 9771 | .dtpoff, | | |
| 9772 | .tpoff, | | |
| 9773 | .size, | | |
| 9774 | => break :r .none, | | |
| 9775 | | 9921 | |
| 9776 | .abs, .pltabs => {}, | 9922 | if (!gsi.ptr(elf).status.want_static_value) { |
| 9777 | } | 9923 | gsi.ptr(elf).status.want_static_value = true; |
| 9778 | if (!@"type".action.simple.dest.isAddr(elf)) break :r .none; | 9924 | try elf.updateGlobalDynamic(gsi, false); |
| 9779 | switch (elf.nodeWantsDsoRelocation(node)) { | | |
| 9780 | .no => break :r .none, | | |
| 9781 | .yes => {}, | | |
| 9782 | .yes_textrel => elf.textrel_count += 1, | | |
| 9783 | } | | |
| 9784 | break :r elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ | | |
| 9785 | .type = .relative(elf), | | |
| 9786 | .offset = node_vaddr + offset, | | |
| 9787 | .raw_sym_index = 0, | | |
| 9788 | .addend = 0, | | |
| 9789 | }).toOptional(); | | |
| 9790 | }, | | |
| 9791 | .dynamic => { | | |
| 9792 | target.unwrap().global.ptr(elf).status.any_dynamic_target_relocs = true; | | |
| 9793 | const dynamic_reloc_type: MachineRelocType = switch (@"type".target) { | | |
| 9794 | // PLT relocations targeting dynamic symbols actually target that symbol's PLT | | |
| 9795 | // entry, so we should emit an `R_*_RELATIVE` relocation instead. | | |
| 9796 | .pltabs => continue :classify .static_relative, | | |
| 9797 | // ...although PC-relative PLT relocations don't even need that! | | |
| 9798 | .pltrel => break :r .none, | | |
| 9799 | // Weird sizes or computations are not supported as runtime relocations. | | |
| 9800 | .special => break :r .none, | | |
| 9801 | // Relative addresses are not supported as runtime relocations. | | |
| 9802 | .rel => break :r .none, | | |
| 9803 | | | |
| 9804 | // On the few targets supporting size relocations, they are valid at runtime. | | |
| 9805 | .size => switch (@"type".action.simple.dest) { | | |
| 9806 | .@"32" => MachineRelocType.size32(elf) orelse break :r .none, | | |
| 9807 | .@"64" => MachineRelocType.size64(elf) orelse break :r .none, | | |
| 9808 | else => break :r .none, | | |
| 9809 | }, | | |
| 9810 | // Absolute addresses and TLS offsets can be lowered at runtime provided they | | |
| 9811 | // are address-sized. | | |
| 9812 | .dtpoff => if (@"type".action.simple.dest.isAddr(elf)) .dtpOff(elf) else break :r .none, | | |
| 9813 | .tpoff => if (@"type".action.simple.dest.isAddr(elf)) .tpOff(elf) else break :r .none, | | |
| 9814 | .abs => if (@"type".action.simple.dest.isAddr(elf)) .absAddr(elf) else break :r .none, | | |
| 9815 | }; | | |
| 9816 | switch (elf.nodeWantsDsoRelocation(node)) { | | |
| 9817 | .no => break :r .none, | | |
| 9818 | .yes => {}, | | |
| 9819 | .yes_textrel => elf.textrel_count += 1, | | |
| 9820 | } | | |
| 9821 | break :r elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ | | |
| 9822 | .type = dynamic_reloc_type, | | |
| 9823 | .offset = node_vaddr + offset, | | |
| 9824 | .raw_sym_index = target.unwrap().global.dynsymIndex(elf).?, | | |
| 9825 | .addend = addend.normal, | | |
| 9826 | }).toOptional(); | | |
| 9827 | }, | | |
| 9828 | } | 9925 | } |
| 9829 | }; | 9926 | } |
| 9830 | | 9927 | |
| 9831 | const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); | 9928 | const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); |
| 9832 | const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc; | 9929 | const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc; |
| ... | @@ -9841,12 +9938,13 @@ fn addSymbolRelocAssumeCapacityInner( | ... | @@ -9841,12 +9938,13 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9841 | .type = @"type", | 9938 | .type = @"type", |
| 9842 | .next = next, | 9939 | .next = next, |
| 9843 | .prev = .none, | 9940 | .prev = .none, |
| 9844 | .rela_index = rela_index, | 9941 | .rela_index = .none, |
| 9845 | .result = .ok, | 9942 | .result = .ok, |
| 9846 | }); | 9943 | }); |
| 9847 | if (@"type".dependsOnTlsSize(elf)) { | 9944 | if (@"type".dependsOnTlsSize(elf)) { |
| 9848 | elf.tls_size_symbol_relocs.putAssumeCapacityNoClobber(ri, {}); | 9945 | elf.tls_size_symbol_relocs.putAssumeCapacityNoClobber(ri, {}); |
| 9849 | } | 9946 | } |
| | 9947 | try ri.get(elf).updateDynamicReloc(elf); |
| 9850 | | 9948 | |
| 9851 | // Actually apply the new relocation! | 9949 | // Actually apply the new relocation! |
| 9852 | ri.get(elf).apply(elf); | 9950 | ri.get(elf).apply(elf); |
| ... | @@ -10177,18 +10275,19 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { | ... | @@ -10177,18 +10275,19 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 10177 | }; | 10275 | }; |
| 10178 | } | 10276 | } |
| 10179 | | 10277 | |
| 10180 | /// If `node` cannot contain runtime relocations, returns `.no`. | 10278 | /// If `node` cannot contain dynamic relocations because it is not loaded into memory at runtime, |
| | 10279 | /// returns `.not_alloc`. |
| 10181 | /// | 10280 | /// |
| 10182 | /// If `node` can contain runtime relocations, returns `.yes_textrel` if such a relocation requires | 10281 | /// Otherwise, returns `.ok_textrel` if placing a dynamic relocation in this node requires the |
| 10183 | /// the presence of a `DT_TEXTREL` dynamic entry, or `.yes` otherwise. | 10282 | /// presence of a `DT_TEXTREL` dynamic entry, or `.ok` otherwise. |
| 10184 | fn nodeWantsDsoRelocation(elf: *Elf, node: MappedFile.Node.Index) enum { yes, yes_textrel, no } { | 10283 | fn nodeAllowsDynamicReloc(elf: *Elf, node: MappedFile.Node.Index) enum { ok, ok_textrel, not_alloc } { |
| 10185 | const shndx = elf.getNodeShndx(node); | 10284 | const shndx = elf.getNodeShndx(node); |
| 10186 | const shf: std.elf.SHF = switch (elf.shdrPtr(shndx)) { | 10285 | const shf: std.elf.SHF = switch (elf.shdrPtr(shndx)) { |
| 10187 | inline else => |shdr| elf.targetLoad(&shdr.flags).shf, | 10286 | inline else => |shdr| elf.targetLoad(&shdr.flags).shf, |
| 10188 | }; | 10287 | }; |
| 10189 | if (!shf.ALLOC) return .no; | 10288 | if (!shf.ALLOC) return .not_alloc; |
| 10190 | if (!shf.WRITE) return .yes_textrel; | 10289 | if (!shf.WRITE) return .ok_textrel; |
| 10191 | return .yes; | 10290 | return .ok; |
| 10192 | } | 10291 | } |
| 10193 | | 10292 | |
| 10194 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { | 10293 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { |
| ... | @@ -10209,15 +10308,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -10209,15 +10308,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 10209 | const nav = ip.getNav(nav_index); | 10308 | const nav = ip.getNav(nav_index); |
| 10210 | const mod = zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?; | 10309 | const mod = zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?; |
| 10211 | switch (ip.indexToKey(nav.resolved.?.value)) { | 10310 | switch (ip.indexToKey(nav.resolved.?.value)) { |
| 10212 | .@"extern" => |@"extern"| { | 10311 | .@"extern" => { |
| 10213 | if (mod.strip or elf.ehdrMachine() != .X86_64) return; | 10312 | if (mod.strip or elf.ehdrMachine() != .X86_64) return; |
| 10214 | const si = try elf.externSymbol(.{ | | |
| 10215 | .name = @"extern".name.toSlice(ip), | | |
| 10216 | .lib_name = @"extern".lib_name.toSlice(ip), | | |
| 10217 | .type = elf.navType(nav.resolved.?), | | |
| 10218 | .linkage = @"extern".linkage, | | |
| 10219 | .visibility = @"extern".visibility, | | |
| 10220 | }); | | |
| 10221 | const dwarf_gi = try elf.dwarf.getGlobal(nav_index); | 10313 | const dwarf_gi = try elf.dwarf.getGlobal(nav_index); |
| 10222 | const dwarf_global = dwarf_gi.get(&elf.dwarf); | 10314 | const dwarf_global = dwarf_gi.get(&elf.dwarf); |
| 10223 | const debug_info_ni = dwarf_global.debug_info_ni.unwrap().?; | 10315 | const debug_info_ni = dwarf_global.debug_info_ni.unwrap().?; |
| ... | @@ -10226,10 +10318,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -10226,10 +10318,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 10226 | debug_info_ni.writer(gpa, &elf.mf, &di_nw); | 10318 | debug_info_ni.writer(gpa, &elf.mf, &di_nw); |
| 10227 | defer di_nw.deinit(); | 10319 | defer di_nw.deinit(); |
| 10228 | elf.resetNodeRelocs(debug_info_ni); | 10320 | elf.resetNodeRelocs(debug_info_ni); |
| 10229 | try elf.dwarf.updateExtern(pt, &di_nw, switch (elf.ehdrMachine()) { | 10321 | try elf.dwarf.updateExtern(pt, &di_nw, nav_index); |
| 10230 | else => unreachable, | | |
| 10231 | .X86_64 => .x86_64, | | |
| 10232 | }, si, nav_index); | | |
| 10233 | }, | 10322 | }, |
| 10234 | else => if (Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) { | 10323 | else => if (Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) { |
| 10235 | const nmi = try elf.navMapIndex(zcu, nav_index); | 10324 | const nmi = try elf.navMapIndex(zcu, nav_index); |
| ... | @@ -10757,10 +10846,28 @@ fn flushInner( | ... | @@ -10757,10 +10846,28 @@ fn flushInner( |
| 10757 | defer elf.mf.nodes_lock.unlock(); | 10846 | defer elf.mf.nodes_lock.unlock(); |
| 10758 | | 10847 | |
| 10759 | if (elf.overflowed_reloc_count > 0) { | 10848 | if (elf.overflowed_reloc_count > 0) { |
| 10760 | diags.addError("failed to apply {d} relocations: overflow", .{elf.overflowed_reloc_count}); | 10849 | diags.addError( |
| | 10850 | "failed to apply {d} relocations: overflow", |
| | 10851 | .{elf.overflowed_reloc_count}, |
| | 10852 | ); |
| 10761 | } | 10853 | } |
| 10762 | if (elf.misaligned_reloc_count > 0) { | 10854 | if (elf.misaligned_reloc_count > 0) { |
| 10763 | diags.addError("failed to apply {d} relocations: misaligned value", .{elf.misaligned_reloc_count}); | 10855 | diags.addError( |
| | 10856 | "failed to apply {d} relocations: misaligned value", |
| | 10857 | .{elf.misaligned_reloc_count}, |
| | 10858 | ); |
| | 10859 | } |
| | 10860 | if (elf.illegal_dynamic_type_reloc_count > 0) { |
| | 10861 | diags.addError( |
| | 10862 | "refusing to emit {d} dynamic relocations with illegal types", |
| | 10863 | .{elf.illegal_dynamic_type_reloc_count}, |
| | 10864 | ); |
| | 10865 | } |
| | 10866 | if (elf.illegal_dynamic_section_reloc_count > 0) { |
| | 10867 | diags.addError( |
| | 10868 | "refusing to emit {d} dynamic relocations in non-allocated sections", |
| | 10869 | .{elf.illegal_dynamic_section_reloc_count}, |
| | 10870 | ); |
| 10764 | } | 10871 | } |
| 10765 | | 10872 | |
| 10766 | if (elf.archive) |*archive| { | 10873 | if (elf.archive) |*archive| { |