| ... | @@ -28,8 +28,10 @@ shdrs: std.ArrayList(Section), | ... | @@ -28,8 +28,10 @@ shdrs: std.ArrayList(Section), |
| 28 | phdrs: std.ArrayList(MappedFile.Node.Index), | 28 | phdrs: std.ArrayList(MappedFile.Node.Index), |
| 29 | shndx: struct { | 29 | shndx: struct { |
| 30 | got: Section.Index, | 30 | got: Section.Index, |
| | 31 | /// Always `.UNDEF` on some targets (e.g. SPARC). |
| 31 | got_plt: Section.Index, | 32 | got_plt: Section.Index, |
| 32 | plt: Section.Index, | 33 | plt: Section.Index, |
| | 34 | /// Only created for x86 targets; `.UNDEF` everywhere else. |
| 33 | plt_sec: Section.Index, | 35 | plt_sec: Section.Index, |
| 34 | dynsym: Section.Index, | 36 | dynsym: Section.Index, |
| 35 | dynstr: Section.Index, | 37 | dynstr: Section.Index, |
| ... | @@ -897,11 +899,12 @@ const GotReloc = struct { | ... | @@ -897,11 +899,12 @@ const GotReloc = struct { |
| 897 | }; | 899 | }; |
| 898 | | 900 | |
| 899 | pub const MachineRelocType = union { | 901 | pub const MachineRelocType = union { |
| 900 | X86_64: std.elf.R_X86_64, | | |
| 901 | AARCH64: std.elf.R_AARCH64, | 902 | AARCH64: std.elf.R_AARCH64, |
| 902 | LOONGARCH: std.elf.R_LARCH, | 903 | LOONGARCH: std.elf.R_LARCH, |
| 903 | RISCV: std.elf.R_RISCV, | | |
| 904 | PPC64: std.elf.R_PPC64, | 904 | PPC64: std.elf.R_PPC64, |
| | 905 | RISCV: std.elf.R_RISCV, |
| | 906 | SPARC: std.elf.R_SPARC, |
| | 907 | X86_64: std.elf.R_X86_64, |
| 905 | | 908 | |
| 906 | pub fn none(elf: *Elf) MachineRelocType { | 909 | pub fn none(elf: *Elf) MachineRelocType { |
| 907 | return switch (elf.ehdrField(.machine)) { | 910 | return switch (elf.ehdrField(.machine)) { |
| ... | @@ -910,6 +913,7 @@ pub const MachineRelocType = union { | ... | @@ -910,6 +913,7 @@ pub const MachineRelocType = union { |
| 910 | .LOONGARCH => .{ .LOONGARCH = .NONE }, | 913 | .LOONGARCH => .{ .LOONGARCH = .NONE }, |
| 911 | .PPC64 => .{ .PPC64 = .NONE }, | 914 | .PPC64 => .{ .PPC64 = .NONE }, |
| 912 | .RISCV => .{ .RISCV = .NONE }, | 915 | .RISCV => .{ .RISCV = .NONE }, |
| | 916 | .SPARCV9 => .{ .SPARC = .NONE }, |
| 913 | .X86_64 => .{ .X86_64 = .NONE }, | 917 | .X86_64 => .{ .X86_64 = .NONE }, |
| 914 | }; | 918 | }; |
| 915 | } | 919 | } |
| ... | @@ -920,6 +924,7 @@ pub const MachineRelocType = union { | ... | @@ -920,6 +924,7 @@ pub const MachineRelocType = union { |
| 920 | .LOONGARCH => .{ .LOONGARCH = .COPY }, | 924 | .LOONGARCH => .{ .LOONGARCH = .COPY }, |
| 921 | .PPC64 => .{ .PPC64 = .COPY }, | 925 | .PPC64 => .{ .PPC64 = .COPY }, |
| 922 | .RISCV => .{ .RISCV = .COPY }, | 926 | .RISCV => .{ .RISCV = .COPY }, |
| | 927 | .SPARCV9 => .{ .SPARC = .COPY }, |
| 923 | .X86_64 => .{ .X86_64 = .COPY }, | 928 | .X86_64 => .{ .X86_64 = .COPY }, |
| 924 | }; | 929 | }; |
| 925 | } | 930 | } |
| ... | @@ -930,43 +935,57 @@ pub const MachineRelocType = union { | ... | @@ -930,43 +935,57 @@ pub const MachineRelocType = union { |
| 930 | .LOONGARCH => .{ .LOONGARCH = .RELATIVE }, | 935 | .LOONGARCH => .{ .LOONGARCH = .RELATIVE }, |
| 931 | .PPC64 => .{ .PPC64 = .RELATIVE }, | 936 | .PPC64 => .{ .PPC64 = .RELATIVE }, |
| 932 | .RISCV => .{ .RISCV = .RELATIVE }, | 937 | .RISCV => .{ .RISCV = .RELATIVE }, |
| | 938 | .SPARCV9 => .{ .SPARC = .RELATIVE }, |
| 933 | .X86_64 => .{ .X86_64 = .RELATIVE }, | 939 | .X86_64 => .{ .X86_64 = .RELATIVE }, |
| 934 | }; | 940 | }; |
| 935 | } | 941 | } |
| 936 | pub fn jumpSlot(elf: *Elf) MachineRelocType { | 942 | pub fn jumpSlot(elf: *Elf) MachineRelocType { |
| 937 | return switch (elf.ehdrField(.machine)) { | 943 | return switch (elf.ehdrField(.machine)) { |
| 938 | else => unreachable, | 944 | else => unreachable, |
| 939 | .X86_64 => .{ .X86_64 = .JUMP_SLOT }, | 945 | .AARCH64 => .{ .AARCH64 = .JUMP_SLOT }, |
| 940 | .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT }, | 946 | .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT }, |
| | 947 | .PPC64 => .{ .PPC64 = .JMP_SLOT }, |
| | 948 | .RISCV => .{ .RISCV = .JUMP_SLOT }, |
| | 949 | .SPARCV9 => .{ .SPARC = .JMP_SLOT }, |
| | 950 | .X86_64 => .{ .X86_64 = .JUMP_SLOT }, |
| 941 | }; | 951 | }; |
| 942 | } | 952 | } |
| 943 | pub fn globDat(elf: *Elf) MachineRelocType { | 953 | pub fn globDat(elf: *Elf) MachineRelocType { |
| 944 | return switch (elf.ehdrField(.machine)) { | 954 | return switch (elf.ehdrField(.machine)) { |
| 945 | else => unreachable, | 955 | else => unreachable, |
| 946 | .X86_64 => .{ .X86_64 = .GLOB_DAT }, | 956 | .AARCH64 => .{ .AARCH64 = .GLOB_DAT }, |
| 947 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | 957 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| | 958 | .PPC64 => .{ .PPC64 = .GLOB_DAT }, |
| | 959 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| | 960 | .SPARCV9 => .{ .SPARC = .GLOB_DAT }, |
| | 961 | .X86_64 => .{ .X86_64 = .GLOB_DAT }, |
| 948 | }; | 962 | }; |
| 949 | } | 963 | } |
| 950 | pub fn dtpOffAddr(elf: *Elf) MachineRelocType { | 964 | pub fn dtpOffAddr(elf: *Elf) MachineRelocType { |
| 951 | return switch (elf.ehdrField(.machine)) { | 965 | return switch (elf.ehdrField(.machine)) { |
| 952 | else => unreachable, | 966 | else => unreachable, |
| 953 | .X86_64 => .{ .X86_64 = .DTPOFF64 }, | | |
| 954 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, | 967 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, |
| | 968 | .PPC64 => .{ .PPC64 = .DTPREL64 }, |
| | 969 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, |
| | 970 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPOFF64 else .TLS_DTPOFF32 }, |
| | 971 | .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .DTPOFF64 else .DTPOFF32 }, |
| 955 | }; | 972 | }; |
| 956 | } | 973 | } |
| 957 | pub fn absAddr(elf: *Elf) MachineRelocType { | 974 | pub fn absAddr(elf: *Elf) MachineRelocType { |
| 958 | return switch (elf.ehdrField(.machine)) { | 975 | return switch (elf.ehdrField(.machine)) { |
| 959 | else => unreachable, | 976 | else => unreachable, |
| 960 | .AARCH64 => .{ .AARCH64 = .ABS64 }, | 977 | .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 }, |
| 961 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | 978 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| 962 | .PPC64 => .{ .PPC64 = .ADDR64 }, | 979 | .PPC64 => .{ .PPC64 = .ADDR64 }, |
| 963 | .RISCV => .{ .RISCV = .@"64" }, | 980 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| 964 | .X86_64 => .{ .X86_64 = .@"64" }, | 981 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| | 982 | .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| 965 | }; | 983 | }; |
| 966 | } | 984 | } |
| 967 | pub fn sizeAddr(elf: *Elf) MachineRelocType { | 985 | pub fn sizeAddr(elf: *Elf) MachineRelocType { |
| 968 | return switch (elf.ehdrField(.machine)) { | 986 | return switch (elf.ehdrField(.machine)) { |
| 969 | else => unreachable, | 987 | else => unreachable, |
| | 988 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .SIZE64 else .SIZE32 }, |
| 970 | .X86_64 => .{ .X86_64 = .SIZE64 }, | 989 | .X86_64 => .{ .X86_64 = .SIZE64 }, |
| 971 | }; | 990 | }; |
| 972 | } | 991 | } |
| ... | @@ -974,6 +993,7 @@ pub const MachineRelocType = union { | ... | @@ -974,6 +993,7 @@ pub const MachineRelocType = union { |
| 974 | pub fn wrap(int: u32, elf: *Elf) MachineRelocType { | 993 | pub fn wrap(int: u32, elf: *Elf) MachineRelocType { |
| 975 | return switch (elf.ehdrField(.machine)) { | 994 | return switch (elf.ehdrField(.machine)) { |
| 976 | else => unreachable, | 995 | else => unreachable, |
| | 996 | .SPARCV9 => .{ .SPARC = @enumFromInt(int) }, |
| 977 | inline .AARCH64, | 997 | inline .AARCH64, |
| 978 | .LOONGARCH, | 998 | .LOONGARCH, |
| 979 | .PPC64, | 999 | .PPC64, |
| ... | @@ -985,6 +1005,7 @@ pub const MachineRelocType = union { | ... | @@ -985,6 +1005,7 @@ pub const MachineRelocType = union { |
| 985 | pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 { | 1005 | pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 { |
| 986 | return switch (elf.ehdrField(.machine)) { | 1006 | return switch (elf.ehdrField(.machine)) { |
| 987 | else => unreachable, | 1007 | else => unreachable, |
| | 1008 | .SPARCV9 => @intFromEnum(rt.SPARC), |
| 988 | inline .AARCH64, | 1009 | inline .AARCH64, |
| 989 | .LOONGARCH, | 1010 | .LOONGARCH, |
| 990 | .PPC64, | 1011 | .PPC64, |
| ... | @@ -1448,10 +1469,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { | ... | @@ -1448,10 +1469,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { |
| 1448 | try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); | 1469 | try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); |
| 1449 | | 1470 | |
| 1450 | // Ensure the `.got.plt` section's node is big enough | 1471 | // Ensure the `.got.plt` section's node is big enough |
| 1451 | const got_plt_need_size: usize = switch (elf.identClass()) { | 1472 | const got_plt_need_size: usize = elf.targetPtrSize() * (3 + need_plt_capacity); |
| 1452 | .NONE, _ => unreachable, | | |
| 1453 | inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity), | | |
| 1454 | }; | | |
| 1455 | try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size); | 1473 | try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size); |
| 1456 | | 1474 | |
| 1457 | // Ensure the `.plt.sec` section's node is big enough | 1475 | // Ensure the `.plt.sec` section's node is big enough |
| ... | @@ -1460,16 +1478,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { | ... | @@ -1460,16 +1478,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { |
| 1460 | }, | 1478 | }, |
| 1461 | .LOONGARCH => { | 1479 | .LOONGARCH => { |
| 1462 | // Ensure the `.plt` section's node is big enough | 1480 | // Ensure the `.plt` section's node is big enough |
| 1463 | const plt_need_size: usize = 32 + 16 * need_plt_capacity; | 1481 | const plt_need_size: usize = 16 * (2 + need_plt_capacity); |
| 1464 | try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); | 1482 | try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); |
| 1465 | | 1483 | |
| 1466 | // Ensure the `.got.plt` section's node is big enough | 1484 | // Ensure the `.got.plt` section's node is big enough |
| 1467 | const got_plt_need_size: usize = switch (elf.identClass()) { | 1485 | const got_plt_need_size: usize = elf.targetPtrSize() * (2 + need_plt_capacity); |
| 1468 | .NONE, _ => unreachable, | | |
| 1469 | inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity), | | |
| 1470 | }; | | |
| 1471 | try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size); | 1486 | try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size); |
| 1472 | }, | 1487 | }, |
| | 1488 | .SPARCV9 => { |
| | 1489 | // Ensure the `.plt` section's node is big enough |
| | 1490 | const plt_need_size: usize = 32 * (4 + need_plt_capacity); |
| | 1491 | try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); |
| | 1492 | }, |
| 1473 | } | 1493 | } |
| 1474 | } | 1494 | } |
| 1475 | /// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at | 1495 | /// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at |
| ... | @@ -2090,23 +2110,17 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -2090,23 +2110,17 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 2090 | .addend = 0, | 2110 | .addend = 0, |
| 2091 | })); | 2111 | })); |
| 2092 | | 2112 | |
| 2093 | const reserved_got_plt_entries: u32 = switch (elf.ehdrField(.machine)) { | 2113 | // Note that some architectures don't have .got.plt (e.g. SPARC), and so |
| | 2114 | // these values actually refer to .plt. |
| | 2115 | const got_plt_section, const got_plt_offset = switch (elf.ehdrField(.machine)) { |
| 2094 | else => |machine| @panic(@tagName(machine)), | 2116 | else => |machine| @panic(@tagName(machine)), |
| 2095 | .X86_64 => 3, | 2117 | .LOONGARCH => .{ elf.shndx.got_plt, elf.targetPtrSize() * (2 + plt_index) }, |
| 2096 | .LOONGARCH => 2, | 2118 | .SPARCV9 => .{ elf.shndx.plt, 32 * (4 + plt_index) }, |
| | 2119 | .X86_64 => .{ elf.shndx.got_plt, elf.targetPtrSize() * (3 + plt_index) }, |
| 2097 | }; | 2120 | }; |
| 2098 | | 2121 | |
| 2099 | // Now that we know the index, we can set the relocation's offset. | 2122 | // Now that we know the index, we can set the relocation's offset. |
| 2100 | const got_plt_addr = switch (elf.shdrPtr(elf.shndx.got_plt)) { | 2123 | elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset); |
| 2101 | inline else => |shdr, class| got_plt_addr: { | | |
| 2102 | const ent_size = @sizeOf(class.ElfN().Addr); | | |
| 2103 | assert(elf.targetLoad(&shdr.entsize) == ent_size); | | |
| 2104 | const offset = ent_size * @as(u64, reserved_got_plt_entries + plt_index); | | |
| 2105 | assert(offset <= elf.targetLoad(&shdr.size)); | | |
| 2106 | break :got_plt_addr elf.targetLoad(&shdr.addr) + offset; | | |
| 2107 | }, | | |
| 2108 | }; | | |
| 2109 | elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_addr); | | |
| 2110 | | 2124 | |
| 2111 | if (plt_index < elf.plt.count()) { | 2125 | if (plt_index < elf.plt.count()) { |
| 2112 | // We reused a free entry, so we're already done! | 2126 | // We reused a free entry, so we're already done! |
| ... | @@ -2148,13 +2162,11 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -2148,13 +2162,11 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 2148 | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; | 2162 | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; |
| 2149 | switch (elf.shdrPtr(elf.shndx.got_plt)) { | 2163 | switch (elf.shdrPtr(elf.shndx.got_plt)) { |
| 2150 | inline else => |shdr, class| { | 2164 | inline else => |shdr, class| { |
| 2151 | const ent_size = @sizeOf(class.ElfN().Addr); | 2165 | assert(elf.targetLoad(&shdr.size) == got_plt_offset); |
| 2152 | const old_size = ent_size * (3 + plt_index); | 2166 | elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(shdr.ElfN().Addr)); |
| 2153 | assert(elf.targetLoad(&shdr.size) == old_size); | | |
| 2154 | elf.targetStore(&shdr.size, old_size + ent_size); | | |
| 2155 | std.mem.writeInt( | 2167 | std.mem.writeInt( |
| 2156 | class.ElfN().Addr, | 2168 | class.ElfN().Addr, |
| 2157 | got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size], | 2169 | got_plt_ni.slice(&elf.mf)[got_plt_offset..][0..@sizeOf(shdr.ElfN().Addr)], |
| 2158 | @intCast(plt_addr), | 2170 | @intCast(plt_addr), |
| 2159 | target_endian, | 2171 | target_endian, |
| 2160 | ); | 2172 | ); |
| ... | @@ -2176,7 +2188,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -2176,7 +2188,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 2176 | i32, | 2188 | i32, |
| 2177 | plt_sec_slice[6..][0..4], | 2189 | plt_sec_slice[6..][0..4], |
| 2178 | @intCast(@as(i64, @bitCast( | 2190 | @intCast(@as(i64, @bitCast( |
| 2179 | got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10), | 2191 | (got_plt_section.vaddr(elf) + got_plt_offset) -% (elf.targetLoad(&shdr.addr) + old_size + 10), |
| 2180 | ))), | 2192 | ))), |
| 2181 | target_endian, | 2193 | target_endian, |
| 2182 | ); | 2194 | ); |
| ... | @@ -2212,26 +2224,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -2212,26 +2224,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 2212 | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; | 2224 | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; |
| 2213 | switch (elf.shdrPtr(elf.shndx.got_plt)) { | 2225 | switch (elf.shdrPtr(elf.shndx.got_plt)) { |
| 2214 | inline else => |shdr, class| { | 2226 | inline else => |shdr, class| { |
| 2215 | const ent_size = @sizeOf(class.ElfN().Addr); | 2227 | assert(elf.targetLoad(&shdr.size) == got_plt_offset); |
| 2216 | const old_size = ent_size * (2 + plt_index); | 2228 | elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(shdr.ElfN().Addr)); |
| 2217 | assert(elf.targetLoad(&shdr.size) == old_size); | | |
| 2218 | elf.targetStore(&shdr.size, old_size + ent_size); | | |
| 2219 | std.mem.writeInt( | 2229 | std.mem.writeInt( |
| 2220 | class.ElfN().Addr, | 2230 | class.ElfN().Addr, |
| 2221 | got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size], | 2231 | got_plt_ni.slice(&elf.mf)[got_plt_offset..][0..@sizeOf(shdr.ElfN().Addr)], |
| 2222 | @intCast(plt_addr), | 2232 | @intCast(plt_addr), |
| 2223 | target_endian, | 2233 | target_endian, |
| 2224 | ); | 2234 | ); |
| 2225 | assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size)); | | |
| 2226 | }, | 2235 | }, |
| 2227 | } | 2236 | } |
| 2228 | | 2237 | |
| 2229 | // relocate the PLT entry to point to the .GOT.PLT entry | 2238 | // relocate the PLT entry to point to the .GOT.PLT entry |
| 2230 | const got_plt_abs: u64 = @as(u64, got_plt_addr); | 2239 | const got_plt_abs = got_plt_section.vaddr(elf) + got_plt_offset; |
| 2231 | // TODO: handle overflow gracefully | 2240 | // TODO: handle overflow gracefully |
| 2232 | link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr)); | 2241 | link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr)); |
| 2233 | link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs)); | 2242 | link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs)); |
| 2234 | }, | 2243 | }, |
| | 2244 | .SPARCV9 => { |
| | 2245 | // add a .PLT entry, writing the template |
| | 2246 | const plt_ni = elf.shndx.plt.get(elf).ni; |
| | 2247 | switch (elf.shdrPtr(elf.shndx.plt)) { |
| | 2248 | inline else => |shdr| { |
| | 2249 | assert(elf.targetLoad(&shdr.size) == got_plt_offset); |
| | 2250 | elf.targetStore(&shdr.size, got_plt_offset + 32); |
| | 2251 | const plt_slice: []u32 = @ptrCast(@alignCast(plt_ni.slice(&elf.mf)[got_plt_offset..][0..32])); |
| | 2252 | // sethi (. - .plt[0]), %g1 |
| | 2253 | // ba,a %xcc, .plt[1] |
| | 2254 | // nop |
| | 2255 | // nop |
| | 2256 | // nop |
| | 2257 | // nop |
| | 2258 | // nop |
| | 2259 | // nop |
| | 2260 | @memcpy(plt_slice, &([2]u32{ |
| | 2261 | // TODO: handle overflow gracefully |
| | 2262 | @bitCast(link.sparc.reloc.Imm22{ |
| | 2263 | .imm22 = @truncate(got_plt_offset), |
| | 2264 | .b22_31 = 0b0000000011, |
| | 2265 | }), |
| | 2266 | @bitCast(link.sparc.reloc.Disp19{ |
| | 2267 | .disp19 = @truncate((got_plt_offset + 4 - 32) >> 2), |
| | 2268 | .b19_31 = 0b1100001101000, |
| | 2269 | }), |
| | 2270 | } ++ @as([6]u32, @splat(0x01000000)))); |
| | 2271 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllElements(u32, plt_slice); |
| | 2272 | }, |
| | 2273 | } |
| | 2274 | }, |
| 2235 | } | 2275 | } |
| 2236 | } | 2276 | } |
| 2237 | | 2277 | |
| ... | @@ -3084,11 +3124,12 @@ fn initHeaders( | ... | @@ -3084,11 +3124,12 @@ fn initHeaders( |
| 3084 | .@"64" => .@"8", | 3124 | .@"64" => .@"8", |
| 3085 | }; | 3125 | }; |
| 3086 | | 3126 | |
| 3087 | const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = | 3127 | const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const got_plt, const plt_sec = |
| 3088 | switch (machine) { | 3128 | switch (machine) { |
| 3089 | else => @panic(@tagName(machine)), | 3129 | else => @panic(@tagName(machine)), |
| 3090 | .X86_64 => .{ 16, .@"16", true }, | 3130 | .LOONGARCH => .{ 16 * 2, .@"4", true, false }, |
| 3091 | .LOONGARCH => .{ 32, .@"4", false }, | 3131 | .SPARCV9 => .{ 32 * 4, .fromByteUnits(256), false, false }, |
| | 3132 | .X86_64 => .{ 16, .@"16", true, true }, |
| 3092 | }; | 3133 | }; |
| 3093 | | 3134 | |
| 3094 | const shnum: u32 = shnum: { | 3135 | const shnum: u32 = shnum: { |
| ... | @@ -3111,7 +3152,7 @@ fn initHeaders( | ... | @@ -3111,7 +3152,7 @@ fn initHeaders( |
| 3111 | } | 3152 | } |
| 3112 | if (@"type" != .REL) { | 3153 | if (@"type" != .REL) { |
| 3113 | shnum += 1; // .got | 3154 | shnum += 1; // .got |
| 3114 | shnum += 1; // .got.plt | 3155 | shnum += @intFromBool(got_plt); // .got.plt |
| 3115 | shnum += 1; // .plt | 3156 | shnum += 1; // .plt |
| 3116 | shnum += @intFromBool(plt_sec); // .plt_sec | 3157 | shnum += @intFromBool(plt_sec); // .plt_sec |
| 3117 | } | 3158 | } |
| ... | @@ -3212,7 +3253,6 @@ fn initHeaders( | ... | @@ -3212,7 +3253,6 @@ fn initHeaders( |
| 3212 | ehdr.phoff = 0; | 3253 | ehdr.phoff = 0; |
| 3213 | ehdr.shoff = 0; | 3254 | ehdr.shoff = 0; |
| 3214 | ehdr.flags = switch (machine) { | 3255 | ehdr.flags = switch (machine) { |
| 3215 | .X86_64 => 0, | | |
| 3216 | .LOONGARCH => e_flags: { | 3256 | .LOONGARCH => e_flags: { |
| 3217 | const target_cpu = &elf.base.comp.getTarget().cpu; | 3257 | const target_cpu = &elf.base.comp.getTarget().cpu; |
| 3218 | const e_flags: std.elf.loongarch.EFlags = .{ | 3258 | const e_flags: std.elf.loongarch.EFlags = .{ |
| ... | @@ -3227,6 +3267,20 @@ fn initHeaders( | ... | @@ -3227,6 +3267,20 @@ fn initHeaders( |
| 3227 | }; | 3267 | }; |
| 3228 | break :e_flags @bitCast(e_flags); | 3268 | break :e_flags @bitCast(e_flags); |
| 3229 | }, | 3269 | }, |
| | 3270 | .SPARCV9 => e_flags: { |
| | 3271 | const e_flags: std.elf.sparc.EFlags = .{ |
| | 3272 | .mm = .rmo, |
| | 3273 | .ext = .{ |
| | 3274 | .@"32plus" = false, |
| | 3275 | .sun_us1 = false, |
| | 3276 | .hal_r1 = false, |
| | 3277 | .sun_us3 = false, |
| | 3278 | .le_data = false, |
| | 3279 | }, |
| | 3280 | }; |
| | 3281 | break :e_flags @bitCast(e_flags); |
| | 3282 | }, |
| | 3283 | .X86_64 => 0, |
| 3230 | else => @panic(@tagName(machine)), | 3284 | else => @panic(@tagName(machine)), |
| 3231 | }; | 3285 | }; |
| 3232 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); | 3286 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); |
| ... | @@ -3324,8 +3378,8 @@ fn initHeaders( | ... | @@ -3324,8 +3378,8 @@ fn initHeaders( |
| 3324 | .@"386" => 0x400000, | 3378 | .@"386" => 0x400000, |
| 3325 | .AARCH64, .X86_64 => 0x200000, | 3379 | .AARCH64, .X86_64 => 0x200000, |
| 3326 | .PPC, .PPC64 => 0x10000000, | 3380 | .PPC, .PPC64 => 0x10000000, |
| 3327 | .S390, .S390_OLD => 0x1000000, | 3381 | .S390 => 0x1000000, |
| 3328 | .OLD_SPARCV9, .SPARCV9 => 0x100000, | 3382 | .SPARCV9 => 0x100000, |
| 3329 | else => 0x10000, | 3383 | else => 0x10000, |
| 3330 | }, | 3384 | }, |
| 3331 | }; | 3385 | }; |
| ... | @@ -3561,14 +3615,16 @@ fn initHeaders( | ... | @@ -3561,14 +3615,16 @@ fn initHeaders( |
| 3561 | // Reserve space for the reserved words, populated later. | 3615 | // Reserve space for the reserved words, populated later. |
| 3562 | .size = switch (machine) { | 3616 | .size = switch (machine) { |
| 3563 | else => @panic(@tagName(machine)), | 3617 | else => @panic(@tagName(machine)), |
| 3564 | .X86_64 => 3 * 8, | 3618 | .X86_64 => 3 * elf.targetPtrSize(), |
| 3565 | .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4, | 3619 | .LOONGARCH, |
| | 3620 | .SPARCV9, |
| | 3621 | => elf.targetPtrSize(), |
| 3566 | }, | 3622 | }, |
| 3567 | .flags = .{ .WRITE = true, .ALLOC = true }, | 3623 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 3568 | .addralign = addr_align, | 3624 | .addralign = addr_align, |
| 3569 | .entsize = @intCast(addr_align.toByteUnits()), | 3625 | .entsize = @intCast(addr_align.toByteUnits()), |
| 3570 | }); | 3626 | }); |
| 3571 | elf.shndx.got_plt = try elf.addSection( | 3627 | if (got_plt) elf.shndx.got_plt = try elf.addSection( |
| 3572 | if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data, | 3628 | if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data, |
| 3573 | .{ | 3629 | .{ |
| 3574 | .name = ".got.plt", | 3630 | .name = ".got.plt", |
| ... | @@ -3578,7 +3634,7 @@ fn initHeaders( | ... | @@ -3578,7 +3634,7 @@ fn initHeaders( |
| 3578 | else => @panic(@tagName(machine)), | 3634 | else => @panic(@tagName(machine)), |
| 3579 | .@"386" => 3 * 4, | 3635 | .@"386" => 3 * 4, |
| 3580 | .X86_64 => 3 * 8, | 3636 | .X86_64 => 3 * 8, |
| 3581 | .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4, | 3637 | .LOONGARCH => 2 * elf.targetPtrSize(), |
| 3582 | }, | 3638 | }, |
| 3583 | .addralign = addr_align, | 3639 | .addralign = addr_align, |
| 3584 | .entsize = @intCast(addr_align.toByteUnits()), | 3640 | .entsize = @intCast(addr_align.toByteUnits()), |
| ... | @@ -3587,7 +3643,14 @@ fn initHeaders( | ... | @@ -3587,7 +3643,14 @@ fn initHeaders( |
| 3587 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ | 3643 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ |
| 3588 | .name = ".plt", | 3644 | .name = ".plt", |
| 3589 | .type = .PROGBITS, | 3645 | .type = .PROGBITS, |
| 3590 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 3646 | .flags = .{ |
| | 3647 | .ALLOC = true, |
| | 3648 | .EXECINSTR = true, |
| | 3649 | .WRITE = switch (machine) { |
| | 3650 | .SPARCV9 => true, |
| | 3651 | else => false, |
| | 3652 | }, |
| | 3653 | }, |
| 3591 | .size = init_plt_size, | 3654 | .size = init_plt_size, |
| 3592 | .addralign = plt_align, | 3655 | .addralign = plt_align, |
| 3593 | .node_align = elf.mf.flags.block_size, | 3656 | .node_align = elf.mf.flags.block_size, |
| ... | @@ -3686,7 +3749,7 @@ fn initHeaders( | ... | @@ -3686,7 +3749,7 @@ fn initHeaders( |
| 3686 | .type = .RELA, | 3749 | .type = .RELA, |
| 3687 | .flags = .{ .ALLOC = true, .INFO_LINK = true }, | 3750 | .flags = .{ .ALLOC = true, .INFO_LINK = true }, |
| 3688 | .link = elf.shndx.dynsym.toSection().?, | 3751 | .link = elf.shndx.dynsym.toSection().?, |
| 3689 | .info = elf.shndx.got_plt.toSection().?, | 3752 | .info = (if (got_plt) elf.shndx.got_plt else elf.shndx.plt).toSection().?, |
| 3690 | .addralign = addr_align, | 3753 | .addralign = addr_align, |
| 3691 | .entsize = rela_size, | 3754 | .entsize = rela_size, |
| 3692 | .node_align = elf.mf.flags.block_size, | 3755 | .node_align = elf.mf.flags.block_size, |
| ... | @@ -3758,6 +3821,7 @@ fn initHeaders( | ... | @@ -3758,6 +3821,7 @@ fn initHeaders( |
| 3758 | try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12); | 3821 | try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12); |
| 3759 | try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12); | 3822 | try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12); |
| 3760 | }, | 3823 | }, |
| | 3824 | .SPARCV9 => {}, |
| 3761 | } | 3825 | } |
| 3762 | } | 3826 | } |
| 3763 | if (comp.config.any_non_single_threaded) { | 3827 | if (comp.config.any_non_single_threaded) { |
| ... | @@ -3782,7 +3846,9 @@ fn initHeaders( | ... | @@ -3782,7 +3846,9 @@ fn initHeaders( |
| 3782 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none); | 3846 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none); |
| 3783 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none); | 3847 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none); |
| 3784 | }, | 3848 | }, |
| 3785 | .LOONGARCH => { | 3849 | .LOONGARCH, |
| | 3850 | .SPARCV9, |
| | 3851 | => { |
| 3786 | try elf.got.ensureUnusedCapacity(gpa, 1); | 3852 | try elf.got.ensureUnusedCapacity(gpa, 1); |
| 3787 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) { | 3853 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) { |
| 3788 | true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) }, | 3854 | true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) }, |
| ... | @@ -4100,12 +4166,11 @@ fn identData(elf: *const Elf) std.elf.DATA { | ... | @@ -4100,12 +4166,11 @@ fn identData(elf: *const Elf) std.elf.DATA { |
| 4100 | return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]); | 4166 | return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]); |
| 4101 | } | 4167 | } |
| 4102 | | 4168 | |
| | 4169 | fn targetPtrSize(elf: *const Elf) u32 { |
| | 4170 | return elf.identClass().size(); |
| | 4171 | } |
| 4103 | fn targetEndian(elf: *const Elf) std.lang.Endian { | 4172 | fn targetEndian(elf: *const Elf) std.lang.Endian { |
| 4104 | return switch (elf.identData()) { | 4173 | return elf.identData().endian(); |
| 4105 | .NONE, _ => unreachable, | | |
| 4106 | .@"2LSB" => .little, | | |
| 4107 | .@"2MSB" => .big, | | |
| 4108 | }; | | |
| 4109 | } | 4174 | } |
| 4110 | fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { | 4175 | fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { |
| 4111 | const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer; | 4176 | const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer; |
| ... | @@ -5462,6 +5527,11 @@ fn prelinkInner(elf: *Elf) Error!void { | ... | @@ -5462,6 +5527,11 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 5462 | }; | 5527 | }; |
| 5463 | } | 5528 | } |
| 5464 | | 5529 | |
| | 5530 | const got_plt = switch (elf.ehdrField(.machine)) { |
| | 5531 | .SPARCV9 => false, |
| | 5532 | else => true, |
| | 5533 | }; |
| | 5534 | |
| 5465 | if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) { | 5535 | if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) { |
| 5466 | .NONE, _ => unreachable, | 5536 | .NONE, _ => unreachable, |
| 5467 | inline else => |ct_class| { | 5537 | inline else => |ct_class| { |
| ... | @@ -5645,7 +5715,7 @@ fn prelinkInner(elf: *Elf) Error!void { | ... | @@ -5645,7 +5715,7 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 5645 | if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity( | 5715 | if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity( |
| 5646 | dynamic_ni, | 5716 | dynamic_ni, |
| 5647 | @sizeOf(ElfN.Addr) * (2 * index + 1), | 5717 | @sizeOf(ElfN.Addr) * (2 * index + 1), |
| 5648 | .local(elf.shndx.got_plt.get(elf).lsi), | 5718 | .local((if (got_plt) elf.shndx.got_plt else elf.shndx.plt).get(elf).lsi), |
| 5649 | 0, | 5719 | 0, |
| 5650 | dsorel, | 5720 | dsorel, |
| 5651 | ); | 5721 | ); |
| ... | @@ -7370,6 +7440,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad | ... | @@ -7370,6 +7440,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 7370 | }, | 7440 | }, |
| 7371 | } | 7441 | } |
| 7372 | }, | 7442 | }, |
| | 7443 | .SPARCV9 => switch (which) { |
| | 7444 | .plt => { |
| | 7445 | // Update the offsets of the relocation entries in `.rela.plt`. |
| | 7446 | const rela_plt_shndx = elf.shndx.rela_plt; |
| | 7447 | for (0..elf.plt.count()) |plt_index| { |
| | 7448 | if (elf.pltEntryIsDead(plt_index)) continue; |
| | 7449 | rela_plt_shndx.relaAdjustOffset(elf, @enumFromInt(plt_index), old_addr, addr); |
| | 7450 | } |
| | 7451 | }, |
| | 7452 | .plt_sec, .got_plt => unreachable, |
| | 7453 | }, |
| 7373 | } | 7454 | } |
| 7374 | } | 7455 | } |
| 7375 | | 7456 | |