| author | |
| committer | |
| log | 5aef08aa09ffbb7c1ea4dff7d5f15dc147ec2ecb |
| tree | 2584faae3b5187ff3c95909b09f98d711caf6524 |
| parent | 58baf6dcdfe5fa4a496e8048e9ba6750719c4e55 |
| signature | Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM |
Partially resolves https://codeberg.org/ziglang/zig/issues/36986, but
does not folly resolve it---the bug still exists in the C backend and
the self-hosted WASM and Mach-O linkers.5 files changed, 46 insertions(+), 30 deletions(-)
lib/std/zig/llvm/Builder.zig+1-1| ... | ... | @@ -3467,7 +3467,7 @@ pub const Global = struct { |
| 3467 | 3467 | try builder.aliases.ensureUnusedCapacity(builder.gpa, 1); |
| 3468 | 3468 | errdefer comptime unreachable; |
| 3469 | 3469 | const alias: Alias.Index = @fromBackingInt(@intCast(builder.aliases.items.len)); |
| 3470 | builder.aliass.appendAssumeCapacity(.{ .global = global, .aliasee = .none }); | |
| 3470 | builder.aliases.appendAssumeCapacity(.{ .global = global, .aliasee = .none }); | |
| 3471 | 3471 | global.ptr(builder).kind = .{ .alias = alias }; |
| 3472 | 3472 | return alias; |
| 3473 | 3473 | } |
src/codegen/llvm.zig+15-25| ... | ... | @@ -1234,7 +1234,6 @@ pub const Object = struct { |
| 1234 | 1234 | // The name, aliasee, and type will be set within this block. Other properties of the |
| 1235 | 1235 | // alias will be set below. |
| 1236 | 1236 | const alias_global: Builder.Global.Index = global: { |
| 1237 | ||
| 1238 | 1237 | // WORKAROUND (see https://github.com/llvm/llvm-project/issues/213504, https://github.com/llvm/llvm-project/issues/214835) |
| 1239 | 1238 | // For NVPTX, LLVM throws "NVPTX aliasee must be a non-kernel function definition" if we try to alias a kernel |
| 1240 | 1239 | // On AMDGCN, LLVM does not generate an alias for the kernel descriptor symbol on associated functions |
| ... | ... | @@ -1256,33 +1255,24 @@ pub const Object = struct { |
| 1256 | 1255 | }; |
| 1257 | 1256 | // There is an existing global with this name, so we can't just create an alias. We |
| 1258 | 1257 | // need to figure out what to do with the existing global instead. |
| 1259 | switch (existing_global.ptrConst(&o.builder).kind) { | |
| 1260 | .alias => |alias| { | |
| 1261 | // We can just repurpose the existing alias. | |
| 1262 | alias.setAliasee(llvm_global.toConst(), &o.builder); | |
| 1263 | alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global.typeOf(&o.builder); | |
| 1264 | alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space; | |
| 1265 | break :global existing_global; | |
| 1258 | const alias: Builder.Alias.Index = switch (existing_global.ptrConst(&o.builder).kind) { | |
| 1259 | .alias => |alias| alias: { | |
| 1260 | // The existing alias is from an earlier export, so if `exp` is weak, ignore it. | |
| 1261 | if (exp.opts.linkage == .weak) return; | |
| 1262 | // But otherwise, we can just repurpose the existing alias. | |
| 1263 | break :alias alias; | |
| 1266 | 1264 | }, |
| 1267 | .variable, .function => { | |
| 1268 | // This must be an extern, which is no good to us---we need an alias. The | |
| 1269 | // extern should refer to the value we're exporting, so replace it with the | |
| 1270 | // exported value. That will free up the name for us to create a new alias. | |
| 1271 | // We need to make a new global which is an alias. Replace this existing one | |
| 1272 | // with the target global, making the name available and fixing references | |
| 1273 | // to this global to point to the target. | |
| 1274 | try existing_global.replace(llvm_global, &o.builder); | |
| 1275 | // The name is now free, so create an alias. | |
| 1276 | const alias = try o.builder.addAlias( | |
| 1277 | exp_name, | |
| 1278 | llvm_global_ty, | |
| 1279 | llvm_global.ptrConst(&o.builder).addr_space, | |
| 1280 | llvm_global.toConst(), | |
| 1281 | ); | |
| 1282 | break :global alias.ptrConst(&o.builder).global; | |
| 1265 | .variable, .function => alias: { | |
| 1266 | // This is an extern which our export resolves, so we can simply convert this | |
| 1267 | // global into the alias we want. | |
| 1268 | break :alias try existing_global.toNewAlias(&o.builder); | |
| 1283 | 1269 | }, |
| 1284 | 1270 | .replaced => unreachable, // a replaced global would have lost the name `exp_name` |
| 1285 | } | |
| 1271 | }; | |
| 1272 | alias.setAliasee(llvm_global.toConst(), &o.builder); | |
| 1273 | alias.ptrConst(&o.builder).global.ptr(&o.builder).type = llvm_global_ty; | |
| 1274 | alias.ptrConst(&o.builder).global.ptr(&o.builder).addr_space = llvm_global.ptrConst(&o.builder).addr_space; | |
| 1275 | break :global existing_global; | |
| 1286 | 1276 | }; |
| 1287 | 1277 | |
| 1288 | 1278 | // We need the alias to *not* be `unnamed_addr` to ensure that the alias address equals |
src/link/Elf/ZigObject.zig+11-4| ... | ... | @@ -1871,6 +1871,17 @@ pub fn updateExports( |
| 1871 | 1871 | |
| 1872 | 1872 | for (export_indices) |export_index| { |
| 1873 | 1873 | const exp = export_index.ptr(zcu); |
| 1874 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); | |
| 1875 | ||
| 1876 | const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null); | |
| 1877 | const global_sym = self.symbol(global_sym_index); | |
| 1878 | const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index]; | |
| 1879 | ||
| 1880 | if (global_esym.st_shndx != std.elf.SHN_UNDEF and exp.opts.linkage == .weak) { | |
| 1881 | // The symbol is already defined by a previous export, so ignore this weak export. | |
| 1882 | continue; | |
| 1883 | } | |
| 1884 | ||
| 1874 | 1885 | const metadata = switch (exp.exported) { |
| 1875 | 1886 | .nav => |nav| blk: { |
| 1876 | 1887 | _ = try self.getOrCreateMetadataForNav(zcu, nav); |
| ... | ... | @@ -1902,18 +1913,14 @@ pub fn updateExports( |
| 1902 | 1913 | .weak => elf.STB_WEAK, |
| 1903 | 1914 | }; |
| 1904 | 1915 | const stt_bits: u8 = @as(u4, @truncate(esym.st_info)); |
| 1905 | const exp_name = exp.opts.name.toSlice(&zcu.intern_pool); | |
| 1906 | 1916 | const name_off = try self.strtab.insert(gpa, exp_name); |
| 1907 | const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null); | |
| 1908 | 1917 | try metadata.exports.append(gpa, global_sym_index); |
| 1909 | 1918 | |
| 1910 | 1919 | const value = self.symbol(sym_index).value; |
| 1911 | const global_sym = self.symbol(global_sym_index); | |
| 1912 | 1920 | global_sym.value = value; |
| 1913 | 1921 | global_sym.flags.weak = exp.opts.linkage == .weak; |
| 1914 | 1922 | global_sym.version_index = elf_file.default_sym_version; |
| 1915 | 1923 | global_sym.ref = .{ .index = esym_shndx, .file = self.index }; |
| 1916 | const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index]; | |
| 1917 | 1924 | global_esym.st_value = @intCast(value); |
| 1918 | 1925 | global_esym.st_shndx = esym.st_shndx; |
| 1919 | 1926 | global_esym.st_info = (stb_bits << 4) | stt_bits; |
test/behavior/extern.zig+17| ... | ... | @@ -66,3 +66,20 @@ test "pass extern function to function" { |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | export fn an_extern_function() void {} |
| 69 | ||
| 70 | test "@extern binds to strong @export over weak @export" { | |
| 71 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/36986 | |
| 72 | ||
| 73 | const sym_name = "extern_binds_to_strong_export_over_weak_export"; | |
| 74 | ||
| 75 | const weak_0: u8 = 42; | |
| 76 | const strong: u8 = 123; | |
| 77 | const weak_1: u8 = 255; | |
| 78 | ||
| 79 | @export(&weak_0, .{ .name = sym_name, .linkage = .weak }); | |
| 80 | @export(&strong, .{ .name = sym_name, .linkage = .strong }); | |
| 81 | @export(&weak_1, .{ .name = sym_name, .linkage = .weak }); | |
| 82 | ||
| 83 | const extern_ptr = @extern(*const u8, .{ .name = sym_name }); | |
| 84 | try expect(extern_ptr.* == strong); | |
| 85 | } |
test/cases/export_override_libc.zig+2| ... | ... | @@ -13,4 +13,6 @@ pub fn main() void { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | // run |
| 16 | // target=x86_64-linux-gnu,x86_64-linux-musl | |
| 17 | // backend=selfhosted,llvm | |
| 16 | 18 | // link_libc=true |