| ... | @@ -749,6 +749,14 @@ const GotReloc = struct { | ... | @@ -749,6 +749,14 @@ const GotReloc = struct { |
| 749 | offset32, | 749 | offset32, |
| 750 | rel64, | 750 | rel64, |
| 751 | rel32, | 751 | rel32, |
| | 752 | |
| | 753 | rel32_hi20, |
| | 754 | rel64_lo20, |
| | 755 | rel64_hi12, |
| | 756 | abs32_lo12, |
| | 757 | abs32_hi20, |
| | 758 | abs64_lo20, |
| | 759 | abs64_hi12, |
| 752 | }; | 760 | }; |
| 753 | | 761 | |
| 754 | const Index = enum(u32) { | 762 | const Index = enum(u32) { |
| ... | @@ -817,6 +825,41 @@ const GotReloc = struct { | ... | @@ -817,6 +825,41 @@ const GotReloc = struct { |
| 817 | @intCast(@as(i64, @bitCast(got_vaddr +% got_offset +% addend -% dest_vaddr))), | 825 | @intCast(@as(i64, @bitCast(got_vaddr +% got_offset +% addend -% dest_vaddr))), |
| 818 | target_endian, | 826 | target_endian, |
| 819 | ), | 827 | ), |
| | 828 | .rel32_hi20 => { |
| | 829 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 830 | const target_value = got_vaddr +% got_offset +% addend; |
| | 831 | link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr)); |
| | 832 | }, |
| | 833 | .rel64_lo20 => { |
| | 834 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 835 | const target_value = got_vaddr +% got_offset +% addend; |
| | 836 | link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr)); |
| | 837 | }, |
| | 838 | .rel64_hi12 => { |
| | 839 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 840 | const target_value = got_vaddr +% got_offset +% addend; |
| | 841 | link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr)); |
| | 842 | }, |
| | 843 | .abs32_lo12 => { |
| | 844 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 845 | const target_value = got_vaddr +% got_offset +% addend; |
| | 846 | link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value)); |
| | 847 | }, |
| | 848 | .abs32_hi20 => { |
| | 849 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 850 | const target_value = got_vaddr +% got_offset +% addend; |
| | 851 | link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12)); |
| | 852 | }, |
| | 853 | .abs64_lo20 => { |
| | 854 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 855 | const target_value = got_vaddr +% got_offset +% addend; |
| | 856 | link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32)); |
| | 857 | }, |
| | 858 | .abs64_hi12 => { |
| | 859 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 860 | const target_value = got_vaddr +% got_offset +% addend; |
| | 861 | link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52)); |
| | 862 | }, |
| 820 | } | 863 | } |
| 821 | } | 864 | } |
| 822 | }; | 865 | }; |
| ... | @@ -824,6 +867,7 @@ const GotReloc = struct { | ... | @@ -824,6 +867,7 @@ const GotReloc = struct { |
| 824 | pub const MachineRelocType = union { | 867 | pub const MachineRelocType = union { |
| 825 | X86_64: std.elf.R_X86_64, | 868 | X86_64: std.elf.R_X86_64, |
| 826 | AARCH64: std.elf.R_AARCH64, | 869 | AARCH64: std.elf.R_AARCH64, |
| | 870 | LOONGARCH: std.elf.R_LARCH, |
| 827 | RISCV: std.elf.R_RISCV, | 871 | RISCV: std.elf.R_RISCV, |
| 828 | PPC64: std.elf.R_PPC64, | 872 | PPC64: std.elf.R_PPC64, |
| 829 | | 873 | |
| ... | @@ -831,6 +875,7 @@ pub const MachineRelocType = union { | ... | @@ -831,6 +875,7 @@ pub const MachineRelocType = union { |
| 831 | return switch (elf.ehdrField(.machine)) { | 875 | return switch (elf.ehdrField(.machine)) { |
| 832 | else => unreachable, | 876 | else => unreachable, |
| 833 | .AARCH64 => .{ .AARCH64 = .NONE }, | 877 | .AARCH64 => .{ .AARCH64 = .NONE }, |
| | 878 | .LOONGARCH => .{ .LOONGARCH = .NONE }, |
| 834 | .PPC64 => .{ .PPC64 = .NONE }, | 879 | .PPC64 => .{ .PPC64 = .NONE }, |
| 835 | .RISCV => .{ .RISCV = .NONE }, | 880 | .RISCV => .{ .RISCV = .NONE }, |
| 836 | .X86_64 => .{ .X86_64 = .NONE }, | 881 | .X86_64 => .{ .X86_64 = .NONE }, |
| ... | @@ -840,6 +885,7 @@ pub const MachineRelocType = union { | ... | @@ -840,6 +885,7 @@ pub const MachineRelocType = union { |
| 840 | return switch (elf.ehdrField(.machine)) { | 885 | return switch (elf.ehdrField(.machine)) { |
| 841 | else => unreachable, | 886 | else => unreachable, |
| 842 | .AARCH64 => .{ .AARCH64 = .COPY }, | 887 | .AARCH64 => .{ .AARCH64 = .COPY }, |
| | 888 | .LOONGARCH => .{ .LOONGARCH = .COPY }, |
| 843 | .PPC64 => .{ .PPC64 = .COPY }, | 889 | .PPC64 => .{ .PPC64 = .COPY }, |
| 844 | .RISCV => .{ .RISCV = .COPY }, | 890 | .RISCV => .{ .RISCV = .COPY }, |
| 845 | .X86_64 => .{ .X86_64 = .COPY }, | 891 | .X86_64 => .{ .X86_64 = .COPY }, |
| ... | @@ -849,24 +895,28 @@ pub const MachineRelocType = union { | ... | @@ -849,24 +895,28 @@ pub const MachineRelocType = union { |
| 849 | return switch (elf.ehdrField(.machine)) { | 895 | return switch (elf.ehdrField(.machine)) { |
| 850 | else => unreachable, | 896 | else => unreachable, |
| 851 | .X86_64 => .{ .X86_64 = .JUMP_SLOT }, | 897 | .X86_64 => .{ .X86_64 = .JUMP_SLOT }, |
| | 898 | .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT }, |
| 852 | }; | 899 | }; |
| 853 | } | 900 | } |
| 854 | pub fn globDat(elf: *Elf) MachineRelocType { | 901 | pub fn globDat(elf: *Elf) MachineRelocType { |
| 855 | return switch (elf.ehdrField(.machine)) { | 902 | return switch (elf.ehdrField(.machine)) { |
| 856 | else => unreachable, | 903 | else => unreachable, |
| 857 | .X86_64 => .{ .X86_64 = .GLOB_DAT }, | 904 | .X86_64 => .{ .X86_64 = .GLOB_DAT }, |
| | 905 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| 858 | }; | 906 | }; |
| 859 | } | 907 | } |
| 860 | pub fn dtpOffAddr(elf: *Elf) MachineRelocType { | 908 | pub fn dtpOffAddr(elf: *Elf) MachineRelocType { |
| 861 | return switch (elf.ehdrField(.machine)) { | 909 | return switch (elf.ehdrField(.machine)) { |
| 862 | else => unreachable, | 910 | else => unreachable, |
| 863 | .X86_64 => .{ .X86_64 = .DTPOFF64 }, | 911 | .X86_64 => .{ .X86_64 = .DTPOFF64 }, |
| | 912 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, |
| 864 | }; | 913 | }; |
| 865 | } | 914 | } |
| 866 | pub fn absAddr(elf: *Elf) MachineRelocType { | 915 | pub fn absAddr(elf: *Elf) MachineRelocType { |
| 867 | return switch (elf.ehdrField(.machine)) { | 916 | return switch (elf.ehdrField(.machine)) { |
| 868 | else => unreachable, | 917 | else => unreachable, |
| 869 | .AARCH64 => .{ .AARCH64 = .ABS64 }, | 918 | .AARCH64 => .{ .AARCH64 = .ABS64 }, |
| | 919 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, |
| 870 | .PPC64 => .{ .PPC64 = .ADDR64 }, | 920 | .PPC64 => .{ .PPC64 = .ADDR64 }, |
| 871 | .RISCV => .{ .RISCV = .@"64" }, | 921 | .RISCV => .{ .RISCV = .@"64" }, |
| 872 | .X86_64 => .{ .X86_64 = .@"64" }, | 922 | .X86_64 => .{ .X86_64 = .@"64" }, |
| ... | @@ -883,6 +933,7 @@ pub const MachineRelocType = union { | ... | @@ -883,6 +933,7 @@ pub const MachineRelocType = union { |
| 883 | return switch (elf.ehdrField(.machine)) { | 933 | return switch (elf.ehdrField(.machine)) { |
| 884 | else => unreachable, | 934 | else => unreachable, |
| 885 | inline .AARCH64, | 935 | inline .AARCH64, |
| | 936 | .LOONGARCH, |
| 886 | .PPC64, | 937 | .PPC64, |
| 887 | .RISCV, | 938 | .RISCV, |
| 888 | .X86_64, | 939 | .X86_64, |
| ... | @@ -893,6 +944,7 @@ pub const MachineRelocType = union { | ... | @@ -893,6 +944,7 @@ pub const MachineRelocType = union { |
| 893 | return switch (elf.ehdrField(.machine)) { | 944 | return switch (elf.ehdrField(.machine)) { |
| 894 | else => unreachable, | 945 | else => unreachable, |
| 895 | inline .AARCH64, | 946 | inline .AARCH64, |
| | 947 | .LOONGARCH, |
| 896 | .PPC64, | 948 | .PPC64, |
| 897 | .RISCV, | 949 | .RISCV, |
| 898 | .X86_64, | 950 | .X86_64, |
| ... | @@ -984,9 +1036,23 @@ const SymbolReloc = struct { | ... | @@ -984,9 +1036,23 @@ const SymbolReloc = struct { |
| 984 | size64, | 1036 | size64, |
| 985 | size32, | 1037 | size32, |
| 986 | | 1038 | |
| | 1039 | abs32_lo12, |
| | 1040 | rel32_hi20, |
| | 1041 | rel64_lo20, |
| | 1042 | rel64_hi12, |
| | 1043 | branch_rel18, |
| | 1044 | branch_rel23, |
| | 1045 | branch_rel28, |
| | 1046 | call_rel38, |
| | 1047 | tpoff32_lo12, |
| | 1048 | tpoff32_hi20, |
| | 1049 | tpoff64_lo20, |
| | 1050 | tpoff64_hi12, |
| | 1051 | |
| 987 | fn dependsOnTlsSize(t: SymbolReloc.Type) bool { | 1052 | fn dependsOnTlsSize(t: SymbolReloc.Type) bool { |
| 988 | return switch (t) { | 1053 | return switch (t) { |
| 989 | .tpoff32, .tpoff64 => true, | 1054 | .tpoff32, .tpoff64 => true, |
| | 1055 | .tpoff32_lo12, .tpoff32_hi20, .tpoff64_lo20, .tpoff64_hi12 => true, |
| 990 | else => false, | 1056 | else => false, |
| 991 | }; | 1057 | }; |
| 992 | } | 1058 | } |
| ... | @@ -1145,6 +1211,67 @@ const SymbolReloc = struct { | ... | @@ -1145,6 +1211,67 @@ const SymbolReloc = struct { |
| 1145 | target_endian, | 1211 | target_endian, |
| 1146 | ); | 1212 | ); |
| 1147 | }, | 1213 | }, |
| | 1214 | .abs32_lo12 => { |
| | 1215 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1216 | link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value)); |
| | 1217 | }, |
| | 1218 | .rel32_hi20 => { |
| | 1219 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1220 | link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr)); |
| | 1221 | }, |
| | 1222 | .rel64_lo20 => { |
| | 1223 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1224 | link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr)); |
| | 1225 | }, |
| | 1226 | .rel64_hi12 => { |
| | 1227 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1228 | link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr)); |
| | 1229 | }, |
| | 1230 | // TODO: handle bad alignment and overflow gracefully |
| | 1231 | .branch_rel18 => { |
| | 1232 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1233 | const target_rel: i64 = @bitCast(target_value -% dest_vaddr); |
| | 1234 | const slot_target: i16 = @intCast(@shrExact(target_rel, 2)); |
| | 1235 | link.loongarch.writeK16(dest_slice[0..4], @bitCast(slot_target)); |
| | 1236 | }, |
| | 1237 | .branch_rel23 => { |
| | 1238 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1239 | const target_rel: i64 = @bitCast(target_value -% dest_vaddr); |
| | 1240 | const slot_target: i21 = @intCast(@shrExact(target_rel, 2)); |
| | 1241 | link.loongarch.writeD5K16(dest_slice[0..4], @bitCast(slot_target)); |
| | 1242 | }, |
| | 1243 | .branch_rel28 => { |
| | 1244 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1245 | const target_rel: i64 = @bitCast(target_value -% dest_vaddr); |
| | 1246 | const slot_target: i26 = @intCast(@shrExact(target_rel, 2)); |
| | 1247 | link.loongarch.writeD10K16(dest_slice[0..4], @bitCast(slot_target)); |
| | 1248 | }, |
| | 1249 | .call_rel38 => { |
| | 1250 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1251 | const target_rel: i64 = @bitCast(target_value -% dest_vaddr); |
| | 1252 | // We use i64 instead of i36 here because the allowed range is |
| | 1253 | // [PC - 128 GiB - 0x20000, PC + 128GiB - 0x20000 - 4]. |
| | 1254 | // The intCast in writeJ20 will do the final check. |
| | 1255 | const slot_target: i64 = @intCast(@shrExact(target_rel, 2)); |
| | 1256 | link.loongarch.writeJ20(dest_slice[0..4], @bitCast(@as(i20, @intCast((slot_target +% 0x8000) >> 16)))); |
| | 1257 | link.loongarch.writeK16(dest_slice[4..8], @bitCast(@as(i16, @truncate(slot_target)))); |
| | 1258 | }, |
| | 1259 | .tpoff32_lo12 => { |
| | 1260 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1261 | link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value)); |
| | 1262 | }, |
| | 1263 | .tpoff32_hi20 => { |
| | 1264 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1265 | link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12)); |
| | 1266 | }, |
| | 1267 | .tpoff64_lo20 => { |
| | 1268 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1269 | link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32)); |
| | 1270 | }, |
| | 1271 | .tpoff64_hi12 => { |
| | 1272 | assert(elf.ehdrField(.machine) == .LOONGARCH); |
| | 1273 | link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52)); |
| | 1274 | }, |
| 1148 | } | 1275 | } |
| 1149 | } | 1276 | } |
| 1150 | | 1277 | |
| ... | @@ -1259,6 +1386,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { | ... | @@ -1259,6 +1386,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { |
| 1259 | const plt_sec_need_size: usize = 16 * need_plt_capacity; | 1386 | const plt_sec_need_size: usize = 16 * need_plt_capacity; |
| 1260 | try elf.ensureNodeSize(elf.shndx.plt_sec.get(elf).ni, plt_sec_need_size); | 1387 | try elf.ensureNodeSize(elf.shndx.plt_sec.get(elf).ni, plt_sec_need_size); |
| 1261 | }, | 1388 | }, |
| | 1389 | .LOONGARCH => { |
| | 1390 | // Ensure the `.plt` section's node is big enough |
| | 1391 | const plt_need_size: usize = 32 + 16 * need_plt_capacity; |
| | 1392 | try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); |
| | 1393 | |
| | 1394 | // Ensure the `.got.plt` section's node is big enough |
| | 1395 | const got_plt_need_size: usize = switch (elf.identClass()) { |
| | 1396 | .NONE, _ => unreachable, |
| | 1397 | inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity), |
| | 1398 | }; |
| | 1399 | try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size); |
| | 1400 | }, |
| 1262 | } | 1401 | } |
| 1263 | } | 1402 | } |
| 1264 | /// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at | 1403 | /// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at |
| ... | @@ -1874,12 +2013,18 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -1874,12 +2013,18 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 1874 | .addend = 0, | 2013 | .addend = 0, |
| 1875 | })); | 2014 | })); |
| 1876 | | 2015 | |
| | 2016 | const reserved_got_plt_entries: u32 = switch (elf.ehdrField(.machine)) { |
| | 2017 | else => |machine| @panic(@tagName(machine)), |
| | 2018 | .X86_64 => 3, |
| | 2019 | .LOONGARCH => 2, |
| | 2020 | }; |
| | 2021 | |
| 1877 | // Now that we know the index, we can set the relocation's offset. | 2022 | // Now that we know the index, we can set the relocation's offset. |
| 1878 | const got_plt_addr = switch (elf.shdrPtr(elf.shndx.got_plt)) { | 2023 | const got_plt_addr = switch (elf.shdrPtr(elf.shndx.got_plt)) { |
| 1879 | inline else => |shdr, class| got_plt_addr: { | 2024 | inline else => |shdr, class| got_plt_addr: { |
| 1880 | const ent_size = @sizeOf(class.ElfN().Addr); | 2025 | const ent_size = @sizeOf(class.ElfN().Addr); |
| 1881 | assert(elf.targetLoad(&shdr.entsize) == ent_size); | 2026 | assert(elf.targetLoad(&shdr.entsize) == ent_size); |
| 1882 | const offset = ent_size * @as(u64, 3 + plt_index); | 2027 | const offset = ent_size * @as(u64, reserved_got_plt_entries + plt_index); |
| 1883 | assert(offset <= elf.targetLoad(&shdr.size)); | 2028 | assert(offset <= elf.targetLoad(&shdr.size)); |
| 1884 | break :got_plt_addr elf.targetLoad(&shdr.addr) + offset; | 2029 | break :got_plt_addr elf.targetLoad(&shdr.addr) + offset; |
| 1885 | }, | 2030 | }, |
| ... | @@ -1961,6 +2106,55 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -1961,6 +2106,55 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 1961 | }, | 2106 | }, |
| 1962 | } | 2107 | } |
| 1963 | }, | 2108 | }, |
| | 2109 | .LOONGARCH => { |
| | 2110 | // add a .PLT entry, writing the template |
| | 2111 | const plt_ni = elf.shndx.plt.get(elf).ni; |
| | 2112 | const plt_addr, const plt_slice = plt_entry: switch (elf.shdrPtr(elf.shndx.plt)) { |
| | 2113 | inline else => |shdr| { |
| | 2114 | const old_size = 16 * (1 + plt_index); |
| | 2115 | assert(elf.targetLoad(&shdr.size) == old_size); |
| | 2116 | elf.targetStore(&shdr.size, old_size + 16); |
| | 2117 | const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16]; |
| | 2118 | @memcpy(plt_slice, source: switch (elf.identClass()) { |
| | 2119 | .NONE, _ => unreachable, |
| | 2120 | inline .@"32", .@"64" => |elf_class| { |
| | 2121 | const ld_byte = if (elf_class == .@"64") 0xc0 else 0x80; |
| | 2122 | break :source &[16]u8{ |
| | 2123 | 0x1a, 0x00, 0x00, 0x0f, // pcalau12i $t3, %pc_hi20(func@.got.plt) |
| | 2124 | 0x28, ld_byte, 0x01, 0xef, // ld.w/d $t3, $t3, %lo12(func@.got.plt) |
| | 2125 | 0x4c, 0x00, 0x01, 0xed, // jirl $t1, $t3, 0 |
| | 2126 | 0x00, 0x2a, 0x00, 0x00, // break |
| | 2127 | }; |
| | 2128 | }, |
| | 2129 | }); |
| | 2130 | break :plt_entry .{ elf.targetLoad(&shdr.addr) + old_size, plt_slice }; |
| | 2131 | }, |
| | 2132 | }; |
| | 2133 | |
| | 2134 | // add a .GOT.PLT entry, writing the address of the corresponding .PLT entry |
| | 2135 | const got_plt_ni = elf.shndx.got_plt.get(elf).ni; |
| | 2136 | switch (elf.shdrPtr(elf.shndx.got_plt)) { |
| | 2137 | inline else => |shdr, class| { |
| | 2138 | const ent_size = @sizeOf(class.ElfN().Addr); |
| | 2139 | const old_size = ent_size * (2 + plt_index); |
| | 2140 | assert(elf.targetLoad(&shdr.size) == old_size); |
| | 2141 | elf.targetStore(&shdr.size, old_size + ent_size); |
| | 2142 | std.mem.writeInt( |
| | 2143 | class.ElfN().Addr, |
| | 2144 | got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size], |
| | 2145 | @intCast(plt_addr), |
| | 2146 | target_endian, |
| | 2147 | ); |
| | 2148 | assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size)); |
| | 2149 | }, |
| | 2150 | } |
| | 2151 | |
| | 2152 | // relocate the PLT entry to point to the .GOT.PLT entry |
| | 2153 | const got_plt_abs: u64 = @as(u64, got_plt_addr); |
| | 2154 | // TODO: handle overflow gracefully |
| | 2155 | link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr)); |
| | 2156 | link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs)); |
| | 2157 | }, |
| 1964 | } | 2158 | } |
| 1965 | } | 2159 | } |
| 1966 | | 2160 | |
| ... | @@ -2715,6 +2909,12 @@ fn initHeaders( | ... | @@ -2715,6 +2909,12 @@ fn initHeaders( |
| 2715 | const relro_phndx = phnum; | 2909 | const relro_phndx = phnum; |
| 2716 | phnum += 1; | 2910 | phnum += 1; |
| 2717 | | 2911 | |
| | 2912 | const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = |
| | 2913 | switch (machine) { |
| | 2914 | else => @panic(@tagName(machine)), |
| | 2915 | .X86_64 => .{ 16, .@"16", true }, |
| | 2916 | .LOONGARCH => .{ 32, .@"4", false }, |
| | 2917 | }; |
| 2718 | const expected_nodes_len = expected_nodes_len: switch (@"type") { | 2918 | const expected_nodes_len = expected_nodes_len: switch (@"type") { |
| 2719 | .NONE, .CORE, _ => unreachable, | 2919 | .NONE, .CORE, _ => unreachable, |
| 2720 | .REL => { | 2920 | .REL => { |
| ... | @@ -2722,9 +2922,10 @@ fn initHeaders( | ... | @@ -2722,9 +2922,10 @@ fn initHeaders( |
| 2722 | defer phnum = 0; | 2922 | defer phnum = 0; |
| 2723 | break :expected_nodes_len 5 + phnum; | 2923 | break :expected_nodes_len 5 + phnum; |
| 2724 | }, | 2924 | }, |
| 2725 | .EXEC, .DYN => break :expected_nodes_len 10 + | 2925 | .EXEC, .DYN => break :expected_nodes_len 9 + |
| 2726 | phnum * 2 - 1 + // each phdr also has a matching shdr, except for the PT_PHDR phdr | 2926 | phnum * 2 - 1 + // each phdr also has a matching shdr, except for the PT_PHDR phdr |
| 2727 | @as(usize, 4) * @intFromBool(have_dynamic_section), // .dynstr, .dynsym, .rela.dyn, .rela.plt | 2927 | @as(usize, 4) * @intFromBool(have_dynamic_section) + // .dynstr, .dynsym, .rela.dyn, .rela.plt |
| | 2928 | @intFromBool(plt_sec), |
| 2728 | }; | 2929 | }; |
| 2729 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); | 2930 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 2730 | try elf.shdrs.ensureTotalCapacity(gpa, shnum); | 2931 | try elf.shdrs.ensureTotalCapacity(gpa, shnum); |
| ... | @@ -3051,6 +3252,7 @@ fn initHeaders( | ... | @@ -3051,6 +3252,7 @@ fn initHeaders( |
| 3051 | .size = switch (machine) { | 3252 | .size = switch (machine) { |
| 3052 | else => @panic(@tagName(machine)), | 3253 | else => @panic(@tagName(machine)), |
| 3053 | .X86_64 => 3 * 8, | 3254 | .X86_64 => 3 * 8, |
| | 3255 | .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4, |
| 3054 | }, | 3256 | }, |
| 3055 | .flags = .{ .WRITE = true, .ALLOC = true }, | 3257 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 3056 | .addralign = addr_align, | 3258 | .addralign = addr_align, |
| ... | @@ -3066,21 +3268,17 @@ fn initHeaders( | ... | @@ -3066,21 +3268,17 @@ fn initHeaders( |
| 3066 | else => @panic(@tagName(machine)), | 3268 | else => @panic(@tagName(machine)), |
| 3067 | .@"386" => 3 * 4, | 3269 | .@"386" => 3 * 4, |
| 3068 | .X86_64 => 3 * 8, | 3270 | .X86_64 => 3 * 8, |
| | 3271 | .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4, |
| 3069 | }, | 3272 | }, |
| 3070 | .addralign = addr_align, | 3273 | .addralign = addr_align, |
| 3071 | .entsize = @intCast(addr_align.toByteUnits()), | 3274 | .entsize = @intCast(addr_align.toByteUnits()), |
| 3072 | }, | 3275 | }, |
| 3073 | ); | 3276 | ); |
| 3074 | const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = | | |
| 3075 | switch (machine) { | | |
| 3076 | else => @panic(@tagName(machine)), | | |
| 3077 | .X86_64 => .{ 16, .@"16", true }, | | |
| 3078 | }; | | |
| 3079 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ | 3277 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ |
| 3080 | .name = ".plt", | 3278 | .name = ".plt", |
| 3081 | .type = .PROGBITS, | 3279 | .type = .PROGBITS, |
| 3082 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 3280 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 3083 | .size = plt_size, | 3281 | .size = init_plt_size, |
| 3084 | .addralign = plt_align, | 3282 | .addralign = plt_align, |
| 3085 | .node_align = elf.mf.flags.block_size, | 3283 | .node_align = elf.mf.flags.block_size, |
| 3086 | }); | 3284 | }); |
| ... | @@ -3218,6 +3416,38 @@ fn initHeaders( | ... | @@ -3218,6 +3416,38 @@ fn initHeaders( |
| 3218 | .{ .X86_64 = .PC32 }, | 3416 | .{ .X86_64 = .PC32 }, |
| 3219 | ); | 3417 | ); |
| 3220 | }, | 3418 | }, |
| | 3419 | .LOONGARCH => { |
| | 3420 | const plt_ni = elf.shndx.plt.get(elf).ni; |
| | 3421 | const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi); |
| | 3422 | @memcpy(plt_ni.slice(&elf.mf)[0..32], switch (class) { |
| | 3423 | .NONE, _ => unreachable, |
| | 3424 | .@"32" => &[32]u8{ |
| | 3425 | 0x1a, 0x00, 0x00, 0x0e, // pcalau12i $t2, %pc_hi20(.got.plt) |
| | 3426 | 0x00, 0x11, 0x3d, 0xad, // sub.w $t1, $t1, $t3 |
| | 3427 | 0x28, 0x80, 0x01, 0xcf, // ld.w $t3, $t2, %lo12(.got.plt) # _dl_runtime_resolve |
| | 3428 | 0x02, 0xbf, 0x51, 0xad, // addi.w $t1, $t1, -44 # .plt entry |
| | 3429 | 0x02, 0x80, 0x01, 0xcc, // addi.w $t0, $t2, %lo12(.got.plt) # &.got.plt |
| | 3430 | 0x00, 0x44, 0x89, 0xad, // srli.w $t1, $t1, 2 # .plt entry offset |
| | 3431 | 0x28, 0x80, 0x11, 0x8c, // ld.w $t0, $t0, 4 # link map |
| | 3432 | 0x4c, 0x00, 0x01, 0xe0, // jr $t3 |
| | 3433 | }, |
| | 3434 | .@"64" => &[32]u8{ |
| | 3435 | 0x1a, 0x00, 0x00, 0x0e, // pcalau12i $t2, %pc_hi20(.got.plt) |
| | 3436 | 0x00, 0x11, 0xbd, 0xad, // sub.d $t1, $t1, $t3 |
| | 3437 | 0x28, 0xc0, 0x01, 0xcf, // ld.d $t3, $t2, %lo12(.got.plt) # _dl_runtime_resolve |
| | 3438 | 0x02, 0xff, 0x51, 0xad, // addi.d $t1, $t1, -44 # .plt entry |
| | 3439 | 0x02, 0xc0, 0x01, 0xcc, // addi.d $t0, $t2, %lo12(.got.plt) # &.got.plt |
| | 3440 | 0x00, 0x45, 0x05, 0xad, // srli.d $t1, $t1, 1 # .plt entry offset |
| | 3441 | 0x28, 0xc0, 0x21, 0x8c, // ld.d $t0, $t0, 8 # link map |
| | 3442 | 0x4c, 0x00, 0x01, 0xe0, // jr $t3 |
| | 3443 | }, |
| | 3444 | }); |
| | 3445 | elf.plt_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len); |
| | 3446 | try elf.ensureUnusedRelocCapacity(plt_ni, 3); |
| | 3447 | try elf.addRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .{ .LOONGARCH = .PCALA_HI20 }); |
| | 3448 | try elf.addRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .{ .LOONGARCH = .PCALA_LO12 }); |
| | 3449 | try elf.addRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .{ .LOONGARCH = .PCALA_LO12 }); |
| | 3450 | }, |
| 3221 | } | 3451 | } |
| 3222 | } | 3452 | } |
| 3223 | if (comp.config.any_non_single_threaded) { | 3453 | if (comp.config.any_non_single_threaded) { |
| ... | @@ -3242,6 +3472,13 @@ fn initHeaders( | ... | @@ -3242,6 +3472,13 @@ fn initHeaders( |
| 3242 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none); | 3472 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none); |
| 3243 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none); | 3473 | elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none); |
| 3244 | }, | 3474 | }, |
| | 3475 | .LOONGARCH => { |
| | 3476 | try elf.got.ensureUnusedCapacity(gpa, 1); |
| | 3477 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) { |
| | 3478 | true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) }, |
| | 3479 | false => .{ .reserved = 0 }, |
| | 3480 | }, .none); |
| | 3481 | }, |
| 3245 | } | 3482 | } |
| 3246 | switch (elf.shdrPtr(elf.shndx.got)) { | 3483 | switch (elf.shdrPtr(elf.shndx.got)) { |
| 3247 | inline else => |shdr, ct_class| { | 3484 | inline else => |shdr, ct_class| { |
| ... | @@ -5375,6 +5612,52 @@ fn addRelocAssumeCapacity( | ... | @@ -5375,6 +5612,52 @@ fn addRelocAssumeCapacity( |
| 5375 | .TLSLD => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .rel32), | 5612 | .TLSLD => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .rel32), |
| 5376 | .GOTTPOFF => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .rel32), | 5613 | .GOTTPOFF => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .rel32), |
| 5377 | }, | 5614 | }, |
| | 5615 | .LOONGARCH => switch (@"type".LOONGARCH) { |
| | 5616 | else => std.debug.panic("TODO: unsupported input relocation, {t}", .{@"type".LOONGARCH}), |
| | 5617 | _, |
| | 5618 | .NONE, |
| | 5619 | .COPY, |
| | 5620 | .JUMP_SLOT, |
| | 5621 | .RELATIVE, |
| | 5622 | .IRELATIVE, |
| | 5623 | => std.debug.panic("TODO: error for illegal or unsupported input relocation, {t}", .{@"type".LOONGARCH}), |
| | 5624 | |
| | 5625 | .RELAX => {}, // TODO: relaxation is not yet implemented |
| | 5626 | |
| | 5627 | // Relocations targeting a symbol |
| | 5628 | .@"64" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs64), |
| | 5629 | .@"32" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32), |
| | 5630 | .@"64_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64), |
| | 5631 | .@"32_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32), |
| | 5632 | |
| | 5633 | .PCALA_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32_lo12), |
| | 5634 | .PCALA_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32_hi20), |
| | 5635 | .PCALA64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_hi12), |
| | 5636 | .PCALA64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_lo20), |
| | 5637 | |
| | 5638 | .B16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel18), |
| | 5639 | .B21 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel23), |
| | 5640 | .B26 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel28), |
| | 5641 | .CALL36 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .call_rel38), |
| | 5642 | |
| | 5643 | // Relocations targeting a TLS symbol |
| | 5644 | .TLS_LE_LO12, .TLS_LE_LO12_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_lo12), |
| | 5645 | .TLS_LE_HI20, .TLS_LE_HI20_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_hi20), |
| | 5646 | .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_lo20), |
| | 5647 | .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_hi12), |
| | 5648 | .TLS_LE_ADD_R => {}, // TODO: relaxation is not yet implemented |
| | 5649 | |
| | 5650 | // Relocations targeting a GOT entry |
| | 5651 | .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12), |
| | 5652 | .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel32_hi20), |
| | 5653 | .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_lo20), |
| | 5654 | .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_hi12), |
| | 5655 | |
| | 5656 | .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12), |
| | 5657 | .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_hi20), |
| | 5658 | .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_lo20), |
| | 5659 | .GOT64_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_hi12), |
| | 5660 | }, |
| 5378 | }, | 5661 | }, |
| 5379 | } | 5662 | } |
| 5380 | } | 5663 | } |
| ... | @@ -5412,7 +5695,47 @@ fn addSymbolRelocAssumeCapacity( | ... | @@ -5412,7 +5695,47 @@ fn addSymbolRelocAssumeCapacity( |
| 5412 | .tpoff32 => .TPOFF32, | 5695 | .tpoff32 => .TPOFF32, |
| 5413 | .size64 => .SIZE64, | 5696 | .size64 => .SIZE64, |
| 5414 | .size32 => .SIZE32, | 5697 | .size32 => .SIZE32, |
| | 5698 | .abs32_lo12, |
| | 5699 | .rel32_hi20, |
| | 5700 | .rel64_lo20, |
| | 5701 | .rel64_hi12, |
| | 5702 | .branch_rel18, |
| | 5703 | .branch_rel23, |
| | 5704 | .branch_rel28, |
| | 5705 | .call_rel38, |
| | 5706 | .tpoff32_lo12, |
| | 5707 | .tpoff32_hi20, |
| | 5708 | .tpoff64_lo20, |
| | 5709 | .tpoff64_hi12, |
| | 5710 | => unreachable, |
| 5415 | } }, | 5711 | } }, |
| | 5712 | .LOONGARCH => .{ |
| | 5713 | .LOONGARCH = switch (@"type") { |
| | 5714 | .write_rela => unreachable, |
| | 5715 | .abs64 => .@"64", |
| | 5716 | .abs32 => .@"32", |
| | 5717 | .abs32s, .size64, .size32 => unreachable, |
| | 5718 | .rel64 => .@"64_PCREL", |
| | 5719 | .rel32 => .@"32_PCREL", |
| | 5720 | .pltrel64, .pltrel32 => break :r .none, |
| | 5721 | .dtpoff64 => .TLS_DTPREL64, |
| | 5722 | .dtpoff32 => .TLS_DTPREL32, |
| | 5723 | .tpoff64 => .TLS_TPREL64, |
| | 5724 | .tpoff32 => .TLS_TPREL32, |
| | 5725 | .abs32_lo12 => .PCALA_LO12, |
| | 5726 | .rel32_hi20 => .PCALA_HI20, |
| | 5727 | .rel64_lo20 => .PCALA64_LO20, |
| | 5728 | .rel64_hi12 => .PCALA64_HI12, |
| | 5729 | .branch_rel18 => .B16, |
| | 5730 | .branch_rel23 => .B21, |
| | 5731 | .branch_rel28 => .B26, |
| | 5732 | .call_rel38 => .CALL36, |
| | 5733 | .tpoff32_lo12 => .TLS_LE_LO12, |
| | 5734 | .tpoff32_hi20 => .TLS_LE_HI20, |
| | 5735 | .tpoff64_lo20 => .TLS_LE64_LO20, |
| | 5736 | .tpoff64_hi12 => .TLS_LE64_HI12, |
| | 5737 | }, |
| | 5738 | }, |
| 5416 | }; | 5739 | }; |
| 5417 | // TODO: even if the symbol is locally defined, preemption/interposition is a | 5740 | // TODO: even if the symbol is locally defined, preemption/interposition is a |
| 5418 | // possibility, which this condition does not currently consider! | 5741 | // possibility, which this condition does not currently consider! |
| ... | @@ -5583,6 +5906,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { | ... | @@ -5583,6 +5906,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 5583 | .type = switch (elf.ehdrField(.machine)) { | 5906 | .type = switch (elf.ehdrField(.machine)) { |
| 5584 | else => |machine| @panic(@tagName(machine)), | 5907 | else => |machine| @panic(@tagName(machine)), |
| 5585 | .X86_64 => .{ .X86_64 = .TPOFF64 }, | 5908 | .X86_64 => .{ .X86_64 = .TPOFF64 }, |
| | 5909 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 }, |
| 5586 | }, | 5910 | }, |
| 5587 | .dynsym_index = switch (sym_id.unwrap()) { | 5911 | .dynsym_index = switch (sym_id.unwrap()) { |
| 5588 | .global => |name| elf.globalByName(name).?.dynsym_index, | 5912 | .global => |name| elf.globalByName(name).?.dynsym_index, |
| ... | @@ -5639,7 +5963,11 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { | ... | @@ -5639,7 +5963,11 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 5639 | .UNDEF => .{ .unsigned = 1 }, // TLS module ID for exexcutable | 5963 | .UNDEF => .{ .unsigned = 1 }, // TLS module ID for exexcutable |
| 5640 | else => .{ | 5964 | else => .{ |
| 5641 | .reloc = .{ | 5965 | .reloc = .{ |
| 5642 | .type = .{ .X86_64 = .DTPMOD64 }, | 5966 | .type = switch (elf.ehdrField(.machine)) { |
| | 5967 | else => |machine| @panic(@tagName(machine)), |
| | 5968 | .X86_64 => .{ .X86_64 = .DTPMOD64 }, |
| | 5969 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, |
| | 5970 | }, |
| 5643 | .dynsym_index = switch (sym.unwrap()) { | 5971 | .dynsym_index = switch (sym.unwrap()) { |
| 5644 | .local => 0, | 5972 | .local => 0, |
| 5645 | .global => |name| dsi: { | 5973 | .global => |name| dsi: { |
| ... | @@ -5671,7 +5999,11 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { | ... | @@ -5671,7 +5999,11 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 5671 | .tlsld0 => switch (elf.shndx.dynamic) { | 5999 | .tlsld0 => switch (elf.shndx.dynamic) { |
| 5672 | .UNDEF => .{ .unsigned = 1 }, // TLS module ID for exexcutable | 6000 | .UNDEF => .{ .unsigned = 1 }, // TLS module ID for exexcutable |
| 5673 | else => .{ .reloc = .{ | 6001 | else => .{ .reloc = .{ |
| 5674 | .type = .{ .X86_64 = .DTPMOD64 }, | 6002 | .type = switch (elf.ehdrField(.machine)) { |
| | 6003 | else => |machine| @panic(@tagName(machine)), |
| | 6004 | .X86_64 => .{ .X86_64 = .DTPMOD64 }, |
| | 6005 | .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, |
| | 6006 | }, |
| 5675 | .dynsym_index = 0, | 6007 | .dynsym_index = 0, |
| 5676 | } }, | 6008 | } }, |
| 5677 | }, | 6009 | }, |
| ... | @@ -6618,6 +6950,55 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad | ... | @@ -6618,6 +6950,55 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 6618 | }, | 6950 | }, |
| 6619 | } | 6951 | } |
| 6620 | }, | 6952 | }, |
| | 6953 | .LOONGARCH => { |
| | 6954 | switch (which) { |
| | 6955 | .plt => { |
| | 6956 | // We also need to update all of the references from `.plt` to `.got.plt`. |
| | 6957 | // However, if there's also a flush pending for `.got.plt`, don't bother doing |
| | 6958 | // this now, because we'll do it when `.got.plt` is flushed anyway. |
| | 6959 | if (elf.shndx.got_plt.get(elf).ni.hasMoved(&elf.mf)) { |
| | 6960 | return; |
| | 6961 | } |
| | 6962 | // Exit this `switch` to update those references. |
| | 6963 | }, |
| | 6964 | .plt_sec => unreachable, |
| | 6965 | .got_plt => { |
| | 6966 | // Update the offsets of the relocation entries in `.rela.plt`. |
| | 6967 | const rela_plt_shndx = elf.shndx.rela_plt; |
| | 6968 | for (0..elf.plt.count()) |plt_index| { |
| | 6969 | if (elf.pltEntryIsDead(plt_index)) continue; |
| | 6970 | rela_plt_shndx.relaAdjustOffset(elf, @enumFromInt(plt_index), old_addr, addr); |
| | 6971 | } |
| | 6972 | // We also need to update all of the references from `.plt` to `.got.plt`. |
| | 6973 | // However, if there's also a flush pending for `.plt`, don't bother doing |
| | 6974 | // this now, because we'll do it when `.plt` is flushed anyway. |
| | 6975 | if (elf.shndx.plt.get(elf).ni.hasMoved(&elf.mf)) { |
| | 6976 | return; |
| | 6977 | } |
| | 6978 | // Exit this `switch` to update those references. |
| | 6979 | }, |
| | 6980 | } |
| | 6981 | // We are updating the references from `.plt` to `.got.plt`. |
| | 6982 | const got_plt_addr = elf.shndx.got_plt.vaddr(elf); |
| | 6983 | const plt_addr = elf.shndx.plt.vaddr(elf); |
| | 6984 | const plt_slice = elf.shndx.plt.get(elf).ni.slice(&elf.mf); |
| | 6985 | switch (elf.identClass()) { |
| | 6986 | .NONE, _ => unreachable, |
| | 6987 | inline else => |class| { |
| | 6988 | const Addr = class.ElfN().Addr; |
| | 6989 | for (0..elf.plt.count()) |plt_index| { |
| | 6990 | const plt_offset = 16 * plt_index; |
| | 6991 | const got_plt_offset = @sizeOf(Addr) * (2 + plt_index); |
| | 6992 | const target_slice = plt_slice[plt_offset..]; |
| | 6993 | |
| | 6994 | const got_plt_abs: u64 = got_plt_addr + got_plt_offset; |
| | 6995 | // TODO: handle overflow gracefully |
| | 6996 | link.loongarch.writeJ20(target_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr + plt_offset)); |
| | 6997 | link.loongarch.writeK12(target_slice[4..8], @truncate(got_plt_abs)); |
| | 6998 | } |
| | 6999 | }, |
| | 7000 | } |
| | 7001 | }, |
| 6621 | } | 7002 | } |
| 6622 | } | 7003 | } |
| 6623 | | 7004 | |