authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-09 15:26:54+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-09 15:26:54+02:00
log01b60634c7edecfd4757e12bc5f3b265a2959761
treef6a0d03ab7c8cadf3c8d58fdc6d04a241a53d197
parent65073f3dc5244941914e7c4d1897a74ac8adcd69
parent1890872b5ecab1788f6d33d57e670b258f7c5805

Merge pull request 'Elf2: add sparc64 support' (#36095) from alexrp/zig:elf2-sparc64 into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36095 Reviewed-by: mlugg <mlugg@noreply.codeberg.org>

4 files changed, 1092 insertions(+), 190 deletions(-)

lib/std/elf.zig+141
......@@ -1644,6 +1644,14 @@ pub const CLASS = enum(u8) {
16441644
16451645 pub const NUM = @typeInfo(CLASS).@"enum".field_names.len;
16461646
1647 pub inline fn size(class: CLASS) u32 {
1648 return switch (class) {
1649 .NONE, _ => unreachable,
1650 .@"32" => 4,
1651 .@"64" => 8,
1652 };
1653 }
1654
16471655 pub fn ElfN(comptime class: CLASS) type {
16481656 return switch (class) {
16491657 .NONE, _ => comptime unreachable,
......@@ -1668,6 +1676,14 @@ pub const DATA = enum(u8) {
16681676 _,
16691677
16701678 pub const NUM = @typeInfo(DATA).@"enum".field_names.len;
1679
1680 pub inline fn endian(data: DATA) std.lang.Endian {
1681 return switch (data) {
1682 .NONE, _ => unreachable,
1683 .@"2LSB" => .little,
1684 .@"2MSB" => .big,
1685 };
1686 }
16711687};
16721688
16731689pub const OSABI = enum(u8) {
......@@ -3136,6 +3152,99 @@ pub const R_LARCH = enum(u32) {
31363152 _,
31373153};
31383154
3155pub const R_SPARC = enum(u32) {
3156 NONE = 0,
3157 @"8" = 1,
3158 @"16" = 2,
3159 @"32" = 3,
3160 DISP8 = 4,
3161 DISP16 = 5,
3162 DISP32 = 6,
3163 WDISP30 = 7,
3164 WDISP22 = 8,
3165 HI22 = 9,
3166 @"22" = 10,
3167 @"13" = 11,
3168 LO10 = 12,
3169 GOT10 = 13,
3170 GOT13 = 14,
3171 GOT22 = 15,
3172 PC10 = 16,
3173 PC22 = 17,
3174 WPLT30 = 18,
3175 COPY = 19,
3176 GLOB_DAT = 20,
3177 JMP_SLOT = 21,
3178 RELATIVE = 22,
3179 UA32 = 23,
3180 PLT32 = 24,
3181 HIPLT22 = 25,
3182 LOPLT10 = 26,
3183 PCPLT32 = 27,
3184 PCPLT22 = 28,
3185 PCPLT10 = 29,
3186 @"10" = 30,
3187 @"11" = 31,
3188 @"64" = 32,
3189 OLO10 = 33,
3190 HH22 = 34,
3191 HM10 = 35,
3192 LM22 = 36,
3193 PC_HH22 = 37,
3194 PC_HM10 = 38,
3195 PC_LM22 = 39,
3196 WDISP16 = 40,
3197 WDISP19 = 41,
3198 @"7" = 43,
3199 @"5" = 44,
3200 @"6" = 45,
3201 DISP64 = 46,
3202 PLT64 = 47,
3203 HIX22 = 48,
3204 LOX10 = 49,
3205 H44 = 50,
3206 M44 = 51,
3207 L44 = 52,
3208 REGISTER = 53,
3209 UA64 = 54,
3210 UA16 = 55,
3211 TLS_GD_HI22 = 56,
3212 TLS_GD_LO10 = 57,
3213 TLS_GD_ADD = 58,
3214 TLS_GD_CALL = 59,
3215 TLS_LDM_HI22 = 60,
3216 TLS_LDM_LO10 = 61,
3217 TLS_LDM_ADD = 62,
3218 TLS_LDM_CALL = 63,
3219 TLS_LDO_HIX22 = 64,
3220 TLS_LDO_LOX10 = 65,
3221 TLS_LDO_ADD = 66,
3222 TLS_IE_HI22 = 67,
3223 TLS_IE_LO10 = 68,
3224 TLS_IE_LD = 69,
3225 TLS_IE_LDX = 70,
3226 TLS_IE_ADD = 71,
3227 TLS_LE_HIX22 = 72,
3228 TLS_LE_LOX10 = 73,
3229 TLS_DTPMOD32 = 74,
3230 TLS_DTPMOD64 = 75,
3231 TLS_DTPOFF32 = 76,
3232 TLS_DTPOFF64 = 77,
3233 TLS_TPOFF32 = 78,
3234 TLS_TPOFF64 = 79,
3235 GOTDATA_HIX22 = 80,
3236 GOTDATA_LOX10 = 81,
3237 GOTDATA_OP_HIX22 = 82,
3238 GOTDATA_OP_LOX10 = 83,
3239 GOTDATA_OP = 84,
3240 H34 = 85,
3241 SIZE32 = 86,
3242 SIZE64 = 87,
3243 WDISP10 = 88,
3244 IRELATIVE = 249,
3245 _,
3246};
3247
31393248pub const ar_hdr = extern struct {
31403249 /// Member file name, sometimes / terminated.
31413250 ar_name: [16]u8,
......@@ -3281,3 +3390,35 @@ pub const loongarch = struct {
32813390 pub const AbiExtension = enum(u3) { base = 0, _ };
32823391 };
32833392};
3393
3394pub const sparc = struct {
3395 pub const EFlags = packed struct(Word) {
3396 mm: MemoryModel,
3397 _reserved1: u6 = 0,
3398 ext: Extensions,
3399 _reserved2: u8 = 0,
3400
3401 pub const MemoryModel = enum(u2) {
3402 /// Total Store Ordering
3403 tso = 0,
3404 /// Partial Store Ordering
3405 pso = 1,
3406 /// Relaxed Memory Ordering
3407 rmo = 2,
3408 };
3409
3410 pub const Extensions = packed struct(u16) {
3411 /// Uses SPARC v8 ABI (w/ 32-bit pointers) on SPARC v9. Also known as v8+.
3412 @"32plus": bool,
3413 /// Uses Sun UltraSPARC extensions.
3414 sun_us1: bool,
3415 /// Uses HaL R1 extensions.
3416 hal_r1: bool,
3417 /// Uses Sun UltraSPARC III extensions.
3418 sun_us3: bool,
3419 _reserved: u11 = 0,
3420 /// Uses little endian data (SPARC v9+).
3421 le_data: bool,
3422 };
3423 };
3424};
src/link.zig+2-1
......@@ -26,12 +26,13 @@ const target_util = @import("target.zig");
2626const codegen = @import("codegen.zig");
2727const crash_report = @import("crash_report.zig");
2828
29pub const aarch64 = @import("link/aarch64.zig");
3029pub const LdScript = @import("link/LdScript.zig");
3130pub const Queue = @import("link/Queue.zig");
3231pub const ConstPool = @import("link/ConstPool.zig");
3332
33pub const aarch64 = @import("link/aarch64.zig");
3434pub const loongarch = @import("link/loongarch.zig");
35pub const sparc = @import("link/sparc.zig");
3536
3637pub const Error = Allocator.Error || Io.Cancelable || error{
3738 /// An error message has already been stored in persistent state on `Compilation` or `Zcu`, for
src/link/Elf2.zig+752-189
......@@ -28,8 +28,10 @@ shdrs: std.ArrayList(Section),
2828phdrs: std.ArrayList(MappedFile.Node.Index),
2929shndx: struct {
3030 got: Section.Index,
31 /// Always `.UNDEF` on some targets (e.g. SPARC).
3132 got_plt: Section.Index,
3233 plt: Section.Index,
34 /// Only created for x86 targets; `.UNDEF` everywhere else.
3335 plt_sec: Section.Index,
3436 dynsym: Section.Index,
3537 dynstr: Section.Index,
......@@ -777,18 +779,26 @@ const GotReloc = struct {
777779 };
778780
779781 const Type = enum(u8) {
780 offset64,
781782 offset32,
782 rel64,
783 offset64,
783784 rel32,
785 rel64,
784786
785 rel32_hi20,
786 rel64_lo20,
787 rel64_hi12,
788 abs32_lo12,
789 abs32_hi20,
790 abs64_lo20,
791 abs64_hi12,
787 larch_rel32_hi20,
788 larch_rel64_lo20,
789 larch_rel64_hi12,
790 larch_abs32_lo12,
791 larch_abs32_hi20,
792 larch_abs64_lo20,
793 larch_abs64_hi12,
794
795 sparc_10,
796 sparc_13,
797 sparc_22,
798 sparc_ldm_hi22,
799 sparc_ldm_lo10,
800 sparc_op_hix22,
801 sparc_op_lox10,
792802 };
793803
794804 const Index = enum(u32) {
......@@ -857,51 +867,96 @@ const GotReloc = struct {
857867 @intCast(@as(i64, @bitCast(got_vaddr +% got_offset +% addend -% dest_vaddr))),
858868 target_endian,
859869 ),
860 .rel32_hi20 => {
870
871 .larch_rel32_hi20 => {
861872 assert(elf.ehdrField(.machine) == .LOONGARCH);
862873 const target_value = got_vaddr +% got_offset +% addend;
863874 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr));
864875 },
865 .rel64_lo20 => {
876 .larch_rel64_lo20 => {
866877 assert(elf.ehdrField(.machine) == .LOONGARCH);
867878 const target_value = got_vaddr +% got_offset +% addend;
868879 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr));
869880 },
870 .rel64_hi12 => {
881 .larch_rel64_hi12 => {
871882 assert(elf.ehdrField(.machine) == .LOONGARCH);
872883 const target_value = got_vaddr +% got_offset +% addend;
873884 link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr));
874885 },
875 .abs32_lo12 => {
886 .larch_abs32_lo12 => {
876887 assert(elf.ehdrField(.machine) == .LOONGARCH);
877888 const target_value = got_vaddr +% got_offset +% addend;
878889 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));
879890 },
880 .abs32_hi20 => {
891 .larch_abs32_hi20 => {
881892 assert(elf.ehdrField(.machine) == .LOONGARCH);
882893 const target_value = got_vaddr +% got_offset +% addend;
883894 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12));
884895 },
885 .abs64_lo20 => {
896 .larch_abs64_lo20 => {
886897 assert(elf.ehdrField(.machine) == .LOONGARCH);
887898 const target_value = got_vaddr +% got_offset +% addend;
888899 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32));
889900 },
890 .abs64_hi12 => {
901 .larch_abs64_hi12 => {
891902 assert(elf.ehdrField(.machine) == .LOONGARCH);
892903 const target_value = got_vaddr +% got_offset +% addend;
893904 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52));
894905 },
906
907 .sparc_10 => {
908 const dest_ptr: *link.sparc.reloc.Simm13 = @ptrCast(@alignCast(dest_slice));
909 var result = elf.targetLoad(dest_ptr);
910 result.simm13 = @as(u10, @truncate(got_offset));
911 elf.targetStore(dest_ptr, result);
912 },
913 .sparc_13 => {
914 const dest_ptr: *link.sparc.reloc.Simm13 = @ptrCast(@alignCast(dest_slice));
915 var result = elf.targetLoad(dest_ptr);
916 result.simm13 = @truncate(got_offset);
917 elf.targetStore(dest_ptr, result);
918 },
919 .sparc_22 => {
920 const dest_ptr: *link.sparc.reloc.Simm22 = @ptrCast(@alignCast(dest_slice));
921 var result = elf.targetLoad(dest_ptr);
922 result.simm22 = @truncate(got_offset >> 10);
923 elf.targetStore(dest_ptr, result);
924 },
925 .sparc_ldm_hi22 => {
926 const dest_ptr: *link.sparc.reloc.Simm22 = @ptrCast(@alignCast(dest_slice));
927 var result = elf.targetLoad(dest_ptr);
928 result.simm22 = @truncate((got_offset +% addend) >> 10);
929 elf.targetStore(dest_ptr, result);
930 },
931 .sparc_ldm_lo10 => {
932 const dest_ptr: *link.sparc.reloc.Simm13 = @ptrCast(@alignCast(dest_slice));
933 var result = elf.targetLoad(dest_ptr);
934 result.simm13 = @as(u10, @truncate(got_offset +% addend));
935 elf.targetStore(dest_ptr, result);
936 },
937 .sparc_op_hix22 => {
938 const dest_ptr: *link.sparc.reloc.Imm22 = @ptrCast(@alignCast(dest_slice));
939 var result = elf.targetLoad(dest_ptr);
940 result.imm22 = @truncate(got_offset >> 10);
941 elf.targetStore(dest_ptr, result);
942 },
943 .sparc_op_lox10 => {
944 const dest_ptr: *link.sparc.reloc.Imm13 = @ptrCast(@alignCast(dest_slice));
945 var result = elf.targetLoad(dest_ptr);
946 result.imm13 = @as(u10, @truncate(got_offset));
947 elf.targetStore(dest_ptr, result);
948 },
895949 }
896950 }
897951};
898952
899953pub const MachineRelocType = union {
900 X86_64: std.elf.R_X86_64,
901954 AARCH64: std.elf.R_AARCH64,
902955 LOONGARCH: std.elf.R_LARCH,
903 RISCV: std.elf.R_RISCV,
904956 PPC64: std.elf.R_PPC64,
957 RISCV: std.elf.R_RISCV,
958 SPARC: std.elf.R_SPARC,
959 X86_64: std.elf.R_X86_64,
905960
906961 pub fn none(elf: *Elf) MachineRelocType {
907962 return switch (elf.ehdrField(.machine)) {
......@@ -910,6 +965,7 @@ pub const MachineRelocType = union {
910965 .LOONGARCH => .{ .LOONGARCH = .NONE },
911966 .PPC64 => .{ .PPC64 = .NONE },
912967 .RISCV => .{ .RISCV = .NONE },
968 .SPARCV9 => .{ .SPARC = .NONE },
913969 .X86_64 => .{ .X86_64 = .NONE },
914970 };
915971 }
......@@ -920,6 +976,7 @@ pub const MachineRelocType = union {
920976 .LOONGARCH => .{ .LOONGARCH = .COPY },
921977 .PPC64 => .{ .PPC64 = .COPY },
922978 .RISCV => .{ .RISCV = .COPY },
979 .SPARCV9 => .{ .SPARC = .COPY },
923980 .X86_64 => .{ .X86_64 = .COPY },
924981 };
925982 }
......@@ -930,43 +987,57 @@ pub const MachineRelocType = union {
930987 .LOONGARCH => .{ .LOONGARCH = .RELATIVE },
931988 .PPC64 => .{ .PPC64 = .RELATIVE },
932989 .RISCV => .{ .RISCV = .RELATIVE },
990 .SPARCV9 => .{ .SPARC = .RELATIVE },
933991 .X86_64 => .{ .X86_64 = .RELATIVE },
934992 };
935993 }
936994 pub fn jumpSlot(elf: *Elf) MachineRelocType {
937995 return switch (elf.ehdrField(.machine)) {
938996 else => unreachable,
939 .X86_64 => .{ .X86_64 = .JUMP_SLOT },
997 .AARCH64 => .{ .AARCH64 = .JUMP_SLOT },
940998 .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT },
999 .PPC64 => .{ .PPC64 = .JMP_SLOT },
1000 .RISCV => .{ .RISCV = .JUMP_SLOT },
1001 .SPARCV9 => .{ .SPARC = .JMP_SLOT },
1002 .X86_64 => .{ .X86_64 = .JUMP_SLOT },
9411003 };
9421004 }
9431005 pub fn globDat(elf: *Elf) MachineRelocType {
9441006 return switch (elf.ehdrField(.machine)) {
9451007 else => unreachable,
946 .X86_64 => .{ .X86_64 = .GLOB_DAT },
1008 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
9471009 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1010 .PPC64 => .{ .PPC64 = .GLOB_DAT },
1011 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1012 .SPARCV9 => .{ .SPARC = .GLOB_DAT },
1013 .X86_64 => .{ .X86_64 = .GLOB_DAT },
9481014 };
9491015 }
9501016 pub fn dtpOffAddr(elf: *Elf) MachineRelocType {
9511017 return switch (elf.ehdrField(.machine)) {
9521018 else => unreachable,
953 .X86_64 => .{ .X86_64 = .DTPOFF64 },
9541019 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },
1020 .PPC64 => .{ .PPC64 = .DTPREL64 },
1021 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },
1022 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPOFF64 else .TLS_DTPOFF32 },
1023 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .DTPOFF64 else .DTPOFF32 },
9551024 };
9561025 }
9571026 pub fn absAddr(elf: *Elf) MachineRelocType {
9581027 return switch (elf.ehdrField(.machine)) {
9591028 else => unreachable,
960 .AARCH64 => .{ .AARCH64 = .ABS64 },
1029 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 },
9611030 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
9621031 .PPC64 => .{ .PPC64 = .ADDR64 },
963 .RISCV => .{ .RISCV = .@"64" },
964 .X86_64 => .{ .X86_64 = .@"64" },
1032 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1033 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1034 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" },
9651035 };
9661036 }
9671037 pub fn sizeAddr(elf: *Elf) MachineRelocType {
9681038 return switch (elf.ehdrField(.machine)) {
9691039 else => unreachable,
1040 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .SIZE64 else .SIZE32 },
9701041 .X86_64 => .{ .X86_64 = .SIZE64 },
9711042 };
9721043 }
......@@ -974,6 +1045,7 @@ pub const MachineRelocType = union {
9741045 pub fn wrap(int: u32, elf: *Elf) MachineRelocType {
9751046 return switch (elf.ehdrField(.machine)) {
9761047 else => unreachable,
1048 .SPARCV9 => .{ .SPARC = @enumFromInt(int) },
9771049 inline .AARCH64,
9781050 .LOONGARCH,
9791051 .PPC64,
......@@ -985,6 +1057,7 @@ pub const MachineRelocType = union {
9851057 pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 {
9861058 return switch (elf.ehdrField(.machine)) {
9871059 else => unreachable,
1060 .SPARCV9 => @intFromEnum(rt.SPARC),
9881061 inline .AARCH64,
9891062 .LOONGARCH,
9901063 .PPC64,
......@@ -1073,37 +1146,67 @@ const SymbolReloc = struct {
10731146 /// This is only used targeting local symbols so can always be statically resolved.
10741147 dsorel32,
10751148
1076 abs64,
1149 abs8,
1150 abs16,
10771151 abs32,
10781152 abs32s,
1079 rel64,
1153 abs64,
1154 rel8,
1155 rel16,
10801156 rel32,
1081 pltrel64,
1157 rel64,
1158 pltabs32,
1159 pltabs64,
10821160 pltrel32,
1083 dtpoff64,
1161 pltrel64,
10841162 dtpoff32,
1085 tpoff64,
1163 dtpoff64,
10861164 tpoff32,
1087 size64,
1165 tpoff64,
10881166 size32,
1167 size64,
10891168
1090 abs32_lo12,
1091 rel32_hi20,
1092 rel64_lo20,
1093 rel64_hi12,
1094 branch_rel18,
1095 branch_rel23,
1096 branch_rel28,
1097 call_rel38,
1098 tpoff32_lo12,
1099 tpoff32_hi20,
1100 tpoff64_lo20,
1101 tpoff64_hi12,
1169 larch_abs32_lo12,
1170 larch_rel32_hi20,
1171 larch_rel64_lo20,
1172 larch_rel64_hi12,
1173 larch_branch_rel18,
1174 larch_branch_rel23,
1175 larch_branch_rel28,
1176 larch_call_rel38,
1177 larch_tpoff32_lo12,
1178 larch_tpoff32_hi20,
1179 larch_tpoff64_lo20,
1180 larch_tpoff64_hi12,
1181
1182 sparc_wdisp30,
1183 sparc_pc10,
1184 sparc_pc22,
1185 sparc_wplt30,
1186 sparc_h44,
1187 sparc_m44,
1188 sparc_l44,
1189 sparc_ldo_hix22,
1190 sparc_ldo_lox10,
1191 sparc_le_hix22,
1192 sparc_le_lox10,
11021193
11031194 fn dependsOnTlsSize(t: SymbolReloc.Type) bool {
11041195 return switch (t) {
1105 .tpoff32, .tpoff64 => true,
1106 .tpoff32_lo12, .tpoff32_hi20, .tpoff64_lo20, .tpoff64_hi12 => true,
1196 .tpoff32,
1197 .tpoff64,
1198 => true,
1199
1200 .larch_tpoff32_lo12,
1201 .larch_tpoff32_hi20,
1202 .larch_tpoff64_lo20,
1203 .larch_tpoff64_hi12,
1204 => true,
1205
1206 .sparc_le_hix22,
1207 .sparc_le_lox10,
1208 => true,
1209
11071210 else => false,
11081211 };
11091212 }
......@@ -1111,8 +1214,18 @@ const SymbolReloc = struct {
11111214 fn isAbsAddr(t: SymbolReloc.Type, elf: *const Elf) bool {
11121215 return switch (elf.identClass()) {
11131216 .NONE, _ => unreachable,
1114 .@"32" => t == .abs32,
1115 .@"64" => t == .abs64,
1217 .@"32" => switch (t) {
1218 .abs32,
1219 .pltabs32,
1220 => true,
1221 else => false,
1222 },
1223 .@"64" => switch (t) {
1224 .abs64,
1225 .pltabs64,
1226 => true,
1227 else => false,
1228 },
11161229 };
11171230 }
11181231 };
......@@ -1131,11 +1244,31 @@ const SymbolReloc = struct {
11311244 .static => unreachable,
11321245 .dynamic => return, // the relocation happens at runtime
11331246 .static_relative => {
1134 assert(reloc.type.isAbsAddr(elf));
11351247 // We have emitted an R_*_RELATIVE relocation to help lower an abs32/abs64 reloc.
11361248 // This is a simplified version of the general relocation handling logic, where we
11371249 // know we're using '.abs64' or '.abs32' (matching the ELF ident class).
1138 const value = reloc.target.value(elf) +% @as(u64, @bitCast(reloc.addend));
1250 const value = type: switch (reloc.type) {
1251 .abs32,
1252 .abs64,
1253 => reloc.target.value(elf) +% @as(u64, @bitCast(reloc.addend)),
1254 .pltabs32,
1255 .pltabs64,
1256 => value: {
1257 const plt_index = switch (reloc.target.unwrap()) {
1258 .local => continue :type .abs32,
1259 .global => |name| elf.plt.getIndex(name) orelse continue :type .abs32,
1260 };
1261 if (elf.pltEntryIsDead(plt_index)) continue :type .abs32;
1262 const plt_shndx: Section.Index, const plt_header_entries: u64, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1263 else => |machine| @panic(@tagName(machine)),
1264 .SPARCV9 => .{ elf.shndx.plt, 4, 32 },
1265 .X86_64 => .{ elf.shndx.plt_sec, 0, 16 },
1266 };
1267 const plt_entry = plt_shndx.vaddr(elf) +% (plt_header_entries + plt_index) * plt_entry_size;
1268 break :value plt_entry +% @as(u64, @bitCast(reloc.addend));
1269 },
1270 else => unreachable,
1271 };
11391272 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, value);
11401273 return;
11411274 },
......@@ -1182,6 +1315,13 @@ const SymbolReloc = struct {
11821315 @intCast(@as(i64, @bitCast(target_value))),
11831316 target_endian,
11841317 ),
1318 .abs16 => std.mem.writeInt(
1319 u16,
1320 dest_slice[0..2],
1321 @intCast(target_value),
1322 target_endian,
1323 ),
1324 .abs8 => dest_slice[0] = @intCast(target_value),
11851325 .rel64 => std.mem.writeInt(
11861326 i64,
11871327 dest_slice[0..8],
......@@ -1194,17 +1334,65 @@ const SymbolReloc = struct {
11941334 @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))),
11951335 target_endian,
11961336 ),
1337 .rel16 => std.mem.writeInt(
1338 i16,
1339 dest_slice[0..2],
1340 @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))),
1341 target_endian,
1342 ),
1343 .rel8 => dest_slice[0] = @bitCast(@as(i8, @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))))),
1344 .pltabs64 => {
1345 const plt_index = switch (reloc.target.unwrap()) {
1346 .local => continue :type .abs64,
1347 .global => |name| elf.plt.getIndex(name) orelse continue :type .abs64,
1348 };
1349 if (elf.pltEntryIsDead(plt_index)) continue :type .abs64;
1350 const plt_shndx: Section.Index, const plt_header_entries: u64, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1351 else => |machine| @panic(@tagName(machine)),
1352 .SPARCV9 => .{ elf.shndx.plt, 4, 32 },
1353 .X86_64 => .{ elf.shndx.plt_sec, 0, 16 },
1354 };
1355 const plt_entry = plt_shndx.vaddr(elf) +% (plt_header_entries + plt_index) * plt_entry_size;
1356 std.mem.writeInt(
1357 i64,
1358 dest_slice[0..8],
1359 @bitCast(plt_entry +% @as(u64, @bitCast(reloc.addend))),
1360 target_endian,
1361 );
1362 },
1363 .pltabs32 => {
1364 const plt_index = switch (reloc.target.unwrap()) {
1365 .local => continue :type .abs32,
1366 .global => |name| elf.plt.getIndex(name) orelse continue :type .abs32,
1367 };
1368 if (elf.pltEntryIsDead(plt_index)) continue :type .abs32;
1369 const plt_shndx: Section.Index, const plt_header_entries: u64, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1370 else => |machine| @panic(@tagName(machine)),
1371 .SPARCV9 => .{ elf.shndx.plt, 4, 32 },
1372 .X86_64 => .{ elf.shndx.plt_sec, 0, 16 },
1373 };
1374 const plt_entry = plt_shndx.vaddr(elf) +% (plt_header_entries + plt_index) * plt_entry_size;
1375 std.mem.writeInt(
1376 i32,
1377 dest_slice[0..4],
1378 @intCast(@as(i64, @bitCast(
1379 plt_entry +% @as(u64, @bitCast(reloc.addend)),
1380 ))),
1381 target_endian,
1382 );
1383 },
11971384 .pltrel64 => {
11981385 const plt_index = switch (reloc.target.unwrap()) {
11991386 .local => continue :type .rel64,
12001387 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel64,
12011388 };
12021389 if (elf.pltEntryIsDead(plt_index)) continue :type .rel64;
1203 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1390 const plt_shndx: Section.Index, const plt_header_entries: u64, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
12041391 else => |machine| @panic(@tagName(machine)),
1205 .X86_64 => .{ elf.shndx.plt_sec, 16 },
1392 .SPARCV9 => .{ elf.shndx.plt, 4, 32 },
1393 .X86_64 => .{ elf.shndx.plt_sec, 0, 16 },
12061394 };
1207 const plt_entry = plt_shndx.vaddr(elf) +% plt_index * plt_entry_size;
1395 const plt_entry = plt_shndx.vaddr(elf) +% (plt_header_entries + plt_index) * plt_entry_size;
12081396 std.mem.writeInt(
12091397 i64,
12101398 dest_slice[0..8],
......@@ -1218,11 +1406,12 @@ const SymbolReloc = struct {
12181406 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel32,
12191407 };
12201408 if (elf.pltEntryIsDead(plt_index)) continue :type .rel32;
1221 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1409 const plt_shndx: Section.Index, const plt_header_entries: u64, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
12221410 else => |machine| @panic(@tagName(machine)),
1223 .X86_64 => .{ elf.shndx.plt_sec, 16 },
1411 .SPARCV9 => .{ elf.shndx.plt, 4, 32 },
1412 .X86_64 => .{ elf.shndx.plt_sec, 0, 16 },
12241413 };
1225 const plt_entry = plt_shndx.vaddr(elf) +% plt_index * plt_entry_size;
1414 const plt_entry = plt_shndx.vaddr(elf) +% (plt_header_entries + plt_index) * plt_entry_size;
12261415 std.mem.writeInt(
12271416 i32,
12281417 dest_slice[0..4],
......@@ -1286,42 +1475,43 @@ const SymbolReloc = struct {
12861475 target_endian,
12871476 );
12881477 },
1289 .abs32_lo12 => {
1478
1479 .larch_abs32_lo12 => {
12901480 assert(elf.ehdrField(.machine) == .LOONGARCH);
12911481 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));
12921482 },
1293 .rel32_hi20 => {
1483 .larch_rel32_hi20 => {
12941484 assert(elf.ehdrField(.machine) == .LOONGARCH);
12951485 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr));
12961486 },
1297 .rel64_lo20 => {
1487 .larch_rel64_lo20 => {
12981488 assert(elf.ehdrField(.machine) == .LOONGARCH);
12991489 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr));
13001490 },
1301 .rel64_hi12 => {
1491 .larch_rel64_hi12 => {
13021492 assert(elf.ehdrField(.machine) == .LOONGARCH);
13031493 link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr));
13041494 },
13051495 // TODO: handle bad alignment and overflow gracefully
1306 .branch_rel18 => {
1496 .larch_branch_rel18 => {
13071497 assert(elf.ehdrField(.machine) == .LOONGARCH);
13081498 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
13091499 const slot_target: i16 = @intCast(@shrExact(target_rel, 2));
13101500 link.loongarch.writeK16(dest_slice[0..4], @bitCast(slot_target));
13111501 },
1312 .branch_rel23 => {
1502 .larch_branch_rel23 => {
13131503 assert(elf.ehdrField(.machine) == .LOONGARCH);
13141504 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
13151505 const slot_target: i21 = @intCast(@shrExact(target_rel, 2));
13161506 link.loongarch.writeD5K16(dest_slice[0..4], @bitCast(slot_target));
13171507 },
1318 .branch_rel28 => {
1508 .larch_branch_rel28 => {
13191509 assert(elf.ehdrField(.machine) == .LOONGARCH);
13201510 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
13211511 const slot_target: i26 = @intCast(@shrExact(target_rel, 2));
13221512 link.loongarch.writeD10K16(dest_slice[0..4], @bitCast(slot_target));
13231513 },
1324 .call_rel38 => {
1514 .larch_call_rel38 => {
13251515 assert(elf.ehdrField(.machine) == .LOONGARCH);
13261516 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
13271517 // We use i64 instead of i36 here because the allowed range is
......@@ -1331,22 +1521,109 @@ const SymbolReloc = struct {
13311521 link.loongarch.writeJ20(dest_slice[0..4], @bitCast(@as(i20, @intCast((slot_target +% 0x8000) >> 16))));
13321522 link.loongarch.writeK16(dest_slice[4..8], @bitCast(@as(i16, @truncate(slot_target))));
13331523 },
1334 .tpoff32_lo12 => {
1524 .larch_tpoff32_lo12 => {
13351525 assert(elf.ehdrField(.machine) == .LOONGARCH);
13361526 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));
13371527 },
1338 .tpoff32_hi20 => {
1528 .larch_tpoff32_hi20 => {
13391529 assert(elf.ehdrField(.machine) == .LOONGARCH);
13401530 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12));
13411531 },
1342 .tpoff64_lo20 => {
1532 .larch_tpoff64_lo20 => {
13431533 assert(elf.ehdrField(.machine) == .LOONGARCH);
13441534 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32));
13451535 },
1346 .tpoff64_hi12 => {
1536 .larch_tpoff64_hi12 => {
13471537 assert(elf.ehdrField(.machine) == .LOONGARCH);
13481538 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52));
13491539 },
1540
1541 .sparc_wdisp30 => {
1542 const dest_ptr: *link.sparc.reloc.Disp30 = @ptrCast(@alignCast(dest_slice));
1543 var result = elf.targetLoad(dest_ptr);
1544 result.disp30 = @truncate((target_value -% dest_vaddr) >> 2);
1545 elf.targetStore(dest_ptr, result);
1546 },
1547 .sparc_pc10 => {
1548 const dest_ptr: *link.sparc.reloc.Simm13 = @ptrCast(@alignCast(dest_slice));
1549 var result = elf.targetLoad(dest_ptr);
1550 result.simm13 = @as(u10, @truncate(target_value -% dest_vaddr));
1551 elf.targetStore(dest_ptr, result);
1552 },
1553 .sparc_pc22 => {
1554 const dest_ptr: *link.sparc.reloc.Disp22 = @ptrCast(@alignCast(dest_slice));
1555 var result = elf.targetLoad(dest_ptr);
1556 result.disp22 = @truncate((target_value -% dest_vaddr) >> 10);
1557 elf.targetStore(dest_ptr, result);
1558 },
1559 .sparc_wplt30 => {
1560 const plt_index = switch (reloc.target.unwrap()) {
1561 .local => continue :type .sparc_wdisp30,
1562 .global => |name| elf.plt.getIndex(name) orelse continue :type .sparc_wdisp30,
1563 };
1564 if (elf.pltEntryIsDead(plt_index)) continue :type .sparc_wdisp30;
1565 const plt_entry = elf.shndx.plt.vaddr(elf) +% (4 + plt_index) * 32;
1566 const dest_ptr: *link.sparc.reloc.Disp30 = @ptrCast(@alignCast(dest_slice));
1567 var result = elf.targetLoad(dest_ptr);
1568 result.disp30 = @truncate((plt_entry +% @as(u64, @bitCast(reloc.addend)) -% dest_vaddr) >> 2);
1569 elf.targetStore(dest_ptr, result);
1570 },
1571 .sparc_h44 => {
1572 const dest_ptr: *link.sparc.reloc.Imm22 = @ptrCast(@alignCast(dest_slice));
1573 var result = elf.targetLoad(dest_ptr);
1574 result.imm22 = @truncate(target_value >> 22);
1575 elf.targetStore(dest_ptr, result);
1576 },
1577 .sparc_m44 => {
1578 const dest_ptr: *link.sparc.reloc.Imm10 = @ptrCast(@alignCast(dest_slice));
1579 var result = elf.targetLoad(dest_ptr);
1580 result.imm10 = @truncate(target_value >> 12);
1581 elf.targetStore(dest_ptr, result);
1582 },
1583 .sparc_l44 => {
1584 const dest_ptr: *link.sparc.reloc.Imm13 = @ptrCast(@alignCast(dest_slice));
1585 var result = elf.targetLoad(dest_ptr);
1586 result.imm13 = @as(u12, @truncate(target_value));
1587 elf.targetStore(dest_ptr, result);
1588 },
1589 .sparc_ldo_hix22 => {
1590 const dest_ptr: *link.sparc.reloc.Simm22 = @ptrCast(@alignCast(dest_slice));
1591 var result = elf.targetLoad(dest_ptr);
1592 result.simm22 = @truncate(target_value >> 10);
1593 elf.targetStore(dest_ptr, result);
1594 },
1595 .sparc_ldo_lox10 => {
1596 const dest_ptr: *link.sparc.reloc.Simm13 = @ptrCast(@alignCast(dest_slice));
1597 var result = elf.targetLoad(dest_ptr);
1598 result.simm13 = @as(u10, @truncate(target_value));
1599 elf.targetStore(dest_ptr, result);
1600 },
1601 .sparc_le_hix22 => {
1602 const tls_phndx = elf.getNode(elf.ni.tls).segment;
1603 const tls_size: u64 = switch (elf.phdrSlice()) {
1604 inline else => |phdr| tls_size: {
1605 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1606 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1607 },
1608 };
1609 const dest_ptr: *link.sparc.reloc.Imm22 = @ptrCast(@alignCast(dest_slice));
1610 var result = elf.targetLoad(dest_ptr);
1611 result.imm22 = @truncate(~(target_value -% tls_size) >> 10);
1612 elf.targetStore(dest_ptr, result);
1613 },
1614 .sparc_le_lox10 => {
1615 const tls_phndx = elf.getNode(elf.ni.tls).segment;
1616 const tls_size: u64 = switch (elf.phdrSlice()) {
1617 inline else => |phdr| tls_size: {
1618 assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS);
1619 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
1620 },
1621 };
1622 const dest_ptr: *link.sparc.reloc.Simm13 = @ptrCast(@alignCast(dest_slice));
1623 var result = elf.targetLoad(dest_ptr);
1624 result.simm13 = @as(u13, 0b1110000000000) | @as(u10, @truncate(target_value -% tls_size));
1625 elf.targetStore(dest_ptr, result);
1626 },
13501627 }
13511628 }
13521629
......@@ -1448,10 +1725,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
14481725 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14491726
14501727 // Ensure the `.got.plt` section's node is big enough
1451 const got_plt_need_size: usize = switch (elf.identClass()) {
1452 .NONE, _ => unreachable,
1453 inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity),
1454 };
1728 const got_plt_need_size: usize = elf.targetPtrSize() * (3 + need_plt_capacity);
14551729 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
14561730
14571731 // Ensure the `.plt.sec` section's node is big enough
......@@ -1460,16 +1734,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
14601734 },
14611735 .LOONGARCH => {
14621736 // Ensure the `.plt` section's node is big enough
1463 const plt_need_size: usize = 32 + 16 * need_plt_capacity;
1737 const plt_need_size: usize = 16 * (2 + need_plt_capacity);
14641738 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14651739
14661740 // Ensure the `.got.plt` section's node is big enough
1467 const got_plt_need_size: usize = switch (elf.identClass()) {
1468 .NONE, _ => unreachable,
1469 inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity),
1470 };
1741 const got_plt_need_size: usize = elf.targetPtrSize() * (2 + need_plt_capacity);
14711742 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
14721743 },
1744 .SPARCV9 => {
1745 // Ensure the `.plt` section's node is big enough
1746 const plt_need_size: usize = 32 * (4 + need_plt_capacity);
1747 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
1748 },
14731749 }
14741750}
14751751/// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at
......@@ -2090,23 +2366,17 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
20902366 .addend = 0,
20912367 }));
20922368
2093 const reserved_got_plt_entries: u32 = switch (elf.ehdrField(.machine)) {
2369 // Note that some architectures don't have .got.plt (e.g. SPARC), and so
2370 // these values actually refer to .plt.
2371 const got_plt_section, const got_plt_offset = switch (elf.ehdrField(.machine)) {
20942372 else => |machine| @panic(@tagName(machine)),
2095 .X86_64 => 3,
2096 .LOONGARCH => 2,
2373 .LOONGARCH => .{ elf.shndx.got_plt, elf.targetPtrSize() * (2 + plt_index) },
2374 .SPARCV9 => .{ elf.shndx.plt, 32 * (4 + plt_index) },
2375 .X86_64 => .{ elf.shndx.got_plt, elf.targetPtrSize() * (3 + plt_index) },
20972376 };
20982377
20992378 // 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)) {
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);
2379 elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset);
21102380
21112381 if (plt_index < elf.plt.count()) {
21122382 // We reused a free entry, so we're already done!
......@@ -2148,13 +2418,11 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
21482418 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
21492419 switch (elf.shdrPtr(elf.shndx.got_plt)) {
21502420 inline else => |shdr, class| {
2151 const ent_size = @sizeOf(class.ElfN().Addr);
2152 const old_size = ent_size * (3 + plt_index);
2153 assert(elf.targetLoad(&shdr.size) == old_size);
2154 elf.targetStore(&shdr.size, old_size + ent_size);
2421 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2422 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(class.ElfN().Addr));
21552423 std.mem.writeInt(
21562424 class.ElfN().Addr,
2157 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],
2425 got_plt_ni.slice(&elf.mf)[got_plt_offset..][0..@sizeOf(class.ElfN().Addr)],
21582426 @intCast(plt_addr),
21592427 target_endian,
21602428 );
......@@ -2176,7 +2444,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
21762444 i32,
21772445 plt_sec_slice[6..][0..4],
21782446 @intCast(@as(i64, @bitCast(
2179 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),
2447 (got_plt_section.vaddr(elf) + got_plt_offset) -% (elf.targetLoad(&shdr.addr) + old_size + 10),
21802448 ))),
21812449 target_endian,
21822450 );
......@@ -2212,26 +2480,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
22122480 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
22132481 switch (elf.shdrPtr(elf.shndx.got_plt)) {
22142482 inline else => |shdr, class| {
2215 const ent_size = @sizeOf(class.ElfN().Addr);
2216 const old_size = ent_size * (2 + plt_index);
2217 assert(elf.targetLoad(&shdr.size) == old_size);
2218 elf.targetStore(&shdr.size, old_size + ent_size);
2483 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2484 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(class.ElfN().Addr));
22192485 std.mem.writeInt(
22202486 class.ElfN().Addr,
2221 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],
2487 got_plt_ni.slice(&elf.mf)[got_plt_offset..][0..@sizeOf(class.ElfN().Addr)],
22222488 @intCast(plt_addr),
22232489 target_endian,
22242490 );
2225 assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size));
22262491 },
22272492 }
22282493
22292494 // relocate the PLT entry to point to the .GOT.PLT entry
2230 const got_plt_abs: u64 = @as(u64, got_plt_addr);
2495 const got_plt_abs = got_plt_section.vaddr(elf) + got_plt_offset;
22312496 // TODO: handle overflow gracefully
22322497 link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr));
22332498 link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs));
22342499 },
2500 .SPARCV9 => {
2501 // add a .PLT entry, writing the template
2502 const plt_ni = elf.shndx.plt.get(elf).ni;
2503 switch (elf.shdrPtr(elf.shndx.plt)) {
2504 inline else => |shdr| {
2505 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2506 elf.targetStore(&shdr.size, got_plt_offset + 32);
2507 const plt_slice: []u32 = @ptrCast(@alignCast(plt_ni.slice(&elf.mf)[got_plt_offset..][0..32]));
2508 // sethi (. - .plt[0]), %g1
2509 // ba,a %xcc, .plt[1]
2510 // nop
2511 // nop
2512 // nop
2513 // nop
2514 // nop
2515 // nop
2516 @memcpy(plt_slice, &([2]u32{
2517 // TODO: handle overflow gracefully
2518 @bitCast(link.sparc.reloc.Imm22{
2519 .imm22 = @truncate(got_plt_offset),
2520 .b22_31 = 0b0000000011,
2521 }),
2522 @bitCast(link.sparc.reloc.Disp19{
2523 .disp19 = @truncate((got_plt_offset + 4 - 32) >> 2),
2524 .b19_31 = 0b1100001101000,
2525 }),
2526 } ++ @as([6]u32, @splat(0x01000000))));
2527 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllElements(u32, plt_slice);
2528 },
2529 }
2530 },
22352531 }
22362532}
22372533
......@@ -2622,12 +2918,12 @@ pub const ExternSymbolOpts = struct {
26222918};
26232919pub fn externSymbol(elf: *Elf, opts: ExternSymbolOpts) link.Error!link.File.SymbolId {
26242920 const diags = &elf.base.comp.link_diags;
2625 return elf.externSymbolInner(opts) catch |err| switch (err) {
2921 return (elf.externSymbolInner(opts) catch |err| switch (err) {
26262922 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
26272923 else => |e| return e,
2628 };
2924 }).toTypeErased();
26292925}
2630fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!link.File.SymbolId {
2926fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!Symbol.Id {
26312927 try elf.ensureUnusedSymbolCapacity(1, .maybe_global);
26322928 const symbol = elf.addGlobalSymbolAssumeCapacity(.{
26332929 .node = .none,
......@@ -2651,7 +2947,7 @@ fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!link.File.SymbolId
26512947 }) catch |err| switch (err) {
26522948 error.MultipleDefinitions => unreachable, // shndx is undef
26532949 };
2654 return symbol.toTypeErased();
2950 return symbol;
26552951}
26562952pub fn addReloc(
26572953 elf: *Elf,
......@@ -3084,11 +3380,12 @@ fn initHeaders(
30843380 .@"64" => .@"8",
30853381 };
30863382
3087 const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =
3383 const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const got_plt, const plt_sec =
30883384 switch (machine) {
30893385 else => @panic(@tagName(machine)),
3090 .X86_64 => .{ 16, .@"16", true },
3091 .LOONGARCH => .{ 32, .@"4", false },
3386 .LOONGARCH => .{ 16 * 2, .@"4", true, false },
3387 .SPARCV9 => .{ 32 * 4, .fromByteUnits(256), false, false },
3388 .X86_64 => .{ 16, .@"16", true, true },
30923389 };
30933390
30943391 const shnum: u32 = shnum: {
......@@ -3111,7 +3408,7 @@ fn initHeaders(
31113408 }
31123409 if (@"type" != .REL) {
31133410 shnum += 1; // .got
3114 shnum += 1; // .got.plt
3411 shnum += @intFromBool(got_plt); // .got.plt
31153412 shnum += 1; // .plt
31163413 shnum += @intFromBool(plt_sec); // .plt_sec
31173414 }
......@@ -3212,7 +3509,6 @@ fn initHeaders(
32123509 ehdr.phoff = 0;
32133510 ehdr.shoff = 0;
32143511 ehdr.flags = switch (machine) {
3215 .X86_64 => 0,
32163512 .LOONGARCH => e_flags: {
32173513 const target_cpu = &elf.base.comp.getTarget().cpu;
32183514 const e_flags: std.elf.loongarch.EFlags = .{
......@@ -3227,6 +3523,20 @@ fn initHeaders(
32273523 };
32283524 break :e_flags @bitCast(e_flags);
32293525 },
3526 .SPARCV9 => e_flags: {
3527 const e_flags: std.elf.sparc.EFlags = .{
3528 .mm = .rmo,
3529 .ext = .{
3530 .@"32plus" = false,
3531 .sun_us1 = false,
3532 .hal_r1 = false,
3533 .sun_us3 = false,
3534 .le_data = false,
3535 },
3536 };
3537 break :e_flags @bitCast(e_flags);
3538 },
3539 .X86_64 => 0,
32303540 else => @panic(@tagName(machine)),
32313541 };
32323542 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
......@@ -3247,6 +3557,31 @@ fn initHeaders(
32473557 }));
32483558 elf.nodes.appendAssumeCapacity(.shdr);
32493559
3560 const page_align: std.mem.Alignment = .fromByteUnits(switch (machine) {
3561 .BPF,
3562 .SPARCV9,
3563 => 0x100000,
3564 .AARCH64,
3565 .AMDGPU,
3566 .QDSP6,
3567 .MIPS,
3568 .PPC,
3569 .PPC64,
3570 .SPARC,
3571 .SPARC32PLUS,
3572 => 0x10000,
3573 .LOONGARCH,
3574 => 0x4000,
3575 .ARC_COMPACT2,
3576 .@"68K",
3577 => 0x2000,
3578 .MSP430,
3579 => 0x4,
3580 .AVR,
3581 => 0x1,
3582 else => 0x1000,
3583 });
3584
32503585 var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: {
32513586 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
32523587 .alignment = elf.mf.flags.block_size,
......@@ -3299,8 +3634,8 @@ fn initHeaders(
32993634 .@"386" => 0x400000,
33003635 .AARCH64, .X86_64 => 0x200000,
33013636 .PPC, .PPC64 => 0x10000000,
3302 .S390, .S390_OLD => 0x1000000,
3303 .OLD_SPARCV9, .SPARCV9 => 0x100000,
3637 .S390 => 0x1000000,
3638 .SPARCV9 => 0x100000,
33043639 else => 0x10000,
33053640 },
33063641 };
......@@ -3351,7 +3686,7 @@ fn initHeaders(
33513686 .filesz = @intCast(rodata_size),
33523687 .memsz = @intCast(rodata_size),
33533688 .flags = .{ .R = true },
3354 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
3689 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).max(page_align).toByteUnits()),
33553690 };
33563691 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
33573692 ph_vaddr += @intCast(rodata_size);
......@@ -3366,7 +3701,7 @@ fn initHeaders(
33663701 .filesz = @intCast(text_size),
33673702 .memsz = @intCast(text_size),
33683703 .flags = .{ .R = true, .X = true },
3369 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
3704 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).max(page_align).toByteUnits()),
33703705 };
33713706 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
33723707 ph_vaddr += @intCast(text_size);
......@@ -3381,7 +3716,7 @@ fn initHeaders(
33813716 .filesz = @intCast(data_size),
33823717 .memsz = @intCast(data_size),
33833718 .flags = .{ .R = true, .W = true },
3384 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
3719 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).max(page_align).toByteUnits()),
33853720 };
33863721 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
33873722 ph_vaddr += @intCast(data_size);
......@@ -3536,14 +3871,16 @@ fn initHeaders(
35363871 // Reserve space for the reserved words, populated later.
35373872 .size = switch (machine) {
35383873 else => @panic(@tagName(machine)),
3539 .X86_64 => 3 * 8,
3540 .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4,
3874 .X86_64 => 3 * elf.targetPtrSize(),
3875 .LOONGARCH,
3876 .SPARCV9,
3877 => elf.targetPtrSize(),
35413878 },
35423879 .flags = .{ .WRITE = true, .ALLOC = true },
35433880 .addralign = addr_align,
35443881 .entsize = @intCast(addr_align.toByteUnits()),
35453882 });
3546 elf.shndx.got_plt = try elf.addSection(
3883 if (got_plt) elf.shndx.got_plt = try elf.addSection(
35473884 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
35483885 .{
35493886 .name = ".got.plt",
......@@ -3553,7 +3890,7 @@ fn initHeaders(
35533890 else => @panic(@tagName(machine)),
35543891 .@"386" => 3 * 4,
35553892 .X86_64 => 3 * 8,
3556 .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4,
3893 .LOONGARCH => 2 * elf.targetPtrSize(),
35573894 },
35583895 .addralign = addr_align,
35593896 .entsize = @intCast(addr_align.toByteUnits()),
......@@ -3562,7 +3899,14 @@ fn initHeaders(
35623899 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
35633900 .name = ".plt",
35643901 .type = .PROGBITS,
3565 .flags = .{ .ALLOC = true, .EXECINSTR = true },
3902 .flags = .{
3903 .ALLOC = true,
3904 .EXECINSTR = true,
3905 .WRITE = switch (machine) {
3906 .SPARCV9 => true,
3907 else => false,
3908 },
3909 },
35663910 .size = init_plt_size,
35673911 .addralign = plt_align,
35683912 .node_align = elf.mf.flags.block_size,
......@@ -3661,7 +4005,7 @@ fn initHeaders(
36614005 .type = .RELA,
36624006 .flags = .{ .ALLOC = true, .INFO_LINK = true },
36634007 .link = elf.shndx.dynsym.toSection().?,
3664 .info = elf.shndx.got_plt.toSection().?,
4008 .info = (if (got_plt) elf.shndx.got_plt else elf.shndx.plt).toSection().?,
36654009 .addralign = addr_align,
36664010 .entsize = rela_size,
36674011 .node_align = elf.mf.flags.block_size,
......@@ -3729,10 +4073,11 @@ fn initHeaders(
37294073 });
37304074 elf.plt_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len);
37314075 try elf.ensureUnusedRelocCapacity(plt_ni, 3);
3732 try elf.addSymbolRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .rel32_hi20);
3733 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12);
3734 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12);
4076 try elf.addSymbolRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .larch_rel32_hi20);
4077 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .larch_abs32_lo12);
4078 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .larch_abs32_lo12);
37354079 },
4080 .SPARCV9 => {},
37364081 }
37374082 }
37384083 if (comp.config.any_non_single_threaded) {
......@@ -3757,7 +4102,9 @@ fn initHeaders(
37574102 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none);
37584103 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none);
37594104 },
3760 .LOONGARCH => {
4105 .LOONGARCH,
4106 .SPARCV9,
4107 => {
37614108 try elf.got.ensureUnusedCapacity(gpa, 1);
37624109 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {
37634110 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
......@@ -4075,35 +4422,38 @@ fn identData(elf: *const Elf) std.elf.DATA {
40754422 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
40764423}
40774424
4425fn targetPtrSize(elf: *const Elf) u32 {
4426 return elf.identClass().size();
4427}
40784428fn targetEndian(elf: *const Elf) std.lang.Endian {
4079 return switch (elf.identData()) {
4080 .NONE, _ => unreachable,
4081 .@"2LSB" => .little,
4082 .@"2MSB" => .big,
4083 };
4429 return elf.identData().endian();
40844430}
40854431fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child {
4086 const Child = @typeInfo(@TypeOf(ptr)).pointer.child;
4432 const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer;
4433 const Child = pointer_ty.child;
4434 const alignment = pointer_ty.attrs.@"align" orelse @alignOf(Child);
40874435 return switch (@typeInfo(Child)) {
40884436 else => @compileError(@typeName(Child)),
40894437 .int => std.mem.toNative(Child, ptr.*, elf.targetEndian()),
4090 .@"enum" => |@"enum"| @enumFromInt(elf.targetLoad(@as(*@"enum".tag_type, @ptrCast(ptr)))),
4438 .@"enum" => |@"enum"| @enumFromInt(elf.targetLoad(@as(*align(alignment) @"enum".tag_type, @ptrCast(ptr)))),
40914439 .@"struct" => |@"struct"| @bitCast(
4092 elf.targetLoad(@as(*@"struct".backing_integer.?, @ptrCast(ptr))),
4440 elf.targetLoad(@as(*align(alignment) @"struct".backing_integer.?, @ptrCast(ptr))),
40934441 ),
40944442 };
40954443}
40964444fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).pointer.child) void {
4097 const Child = @typeInfo(@TypeOf(ptr)).pointer.child;
4445 const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer;
4446 const Child = pointer_ty.child;
4447 const alignment = pointer_ty.attrs.@"align" orelse @alignOf(Child);
40984448 return switch (@typeInfo(Child)) {
40994449 else => @compileError(@typeName(Child)),
41004450 .int => ptr.* = std.mem.nativeTo(Child, val, elf.targetEndian()),
41014451 .@"enum" => |@"enum"| elf.targetStore(
4102 @as(*@"enum".tag_type, @ptrCast(ptr)),
4452 @as(*align(alignment) @"enum".tag_type, @ptrCast(ptr)),
41034453 @intFromEnum(val),
41044454 ),
41054455 .@"struct" => |@"struct"| elf.targetStore(
4106 @as(*@"struct".backing_integer.?, @ptrCast(ptr)),
4456 @as(*align(alignment) @"struct".backing_integer.?, @ptrCast(ptr)),
41074457 @bitCast(val),
41084458 ),
41094459 };
......@@ -5433,6 +5783,11 @@ fn prelinkInner(elf: *Elf) Error!void {
54335783 };
54345784 }
54355785
5786 const got_plt = switch (elf.ehdrField(.machine)) {
5787 .SPARCV9 => false,
5788 else => true,
5789 };
5790
54365791 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
54375792 .NONE, _ => unreachable,
54385793 inline else => |ct_class| {
......@@ -5616,7 +5971,7 @@ fn prelinkInner(elf: *Elf) Error!void {
56165971 if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity(
56175972 dynamic_ni,
56185973 @sizeOf(ElfN.Addr) * (2 * index + 1),
5619 .local(elf.shndx.got_plt.get(elf).lsi),
5974 .local((if (got_plt) elf.shndx.got_plt else elf.shndx.plt).get(elf).lsi),
56205975 0,
56215976 dsorel,
56225977 );
......@@ -5938,33 +6293,141 @@ fn addRelocAssumeCapacity(
59386293 .@"64_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64),
59396294 .@"32_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32),
59406295
5941 .PCALA_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32_lo12),
5942 .PCALA_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32_hi20),
5943 .PCALA64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_hi12),
5944 .PCALA64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_lo20),
6296 .PCALA_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_abs32_lo12),
6297 .PCALA_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_rel32_hi20),
6298 .PCALA64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_rel64_hi12),
6299 .PCALA64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_rel64_lo20),
59456300
5946 .B16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel18),
5947 .B21 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel23),
5948 .B26 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel28),
5949 .CALL36 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .call_rel38),
6301 .B16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_branch_rel18),
6302 .B21 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_branch_rel23),
6303 .B26 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_branch_rel28),
6304 .CALL36 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_call_rel38),
59506305
59516306 // Relocations targeting a TLS symbol
5952 .TLS_LE_LO12, .TLS_LE_LO12_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_lo12),
5953 .TLS_LE_HI20, .TLS_LE_HI20_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_hi20),
5954 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_lo20),
5955 .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_hi12),
6307 .TLS_LE_LO12, .TLS_LE_LO12_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff32_lo12),
6308 .TLS_LE_HI20, .TLS_LE_HI20_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff32_hi20),
6309 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff64_lo20),
6310 .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff64_hi12),
59566311 .TLS_LE_ADD_R => {}, // TODO: relaxation is not yet implemented
59576312
59586313 // Relocations targeting a GOT entry
5959 .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12),
5960 .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel32_hi20),
5961 .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_lo20),
5962 .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_hi12),
5963
5964 .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12),
5965 .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_hi20),
5966 .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_lo20),
5967 .GOT64_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_hi12),
6314 .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs32_lo12),
6315 .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_rel32_hi20),
6316 .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_rel64_lo20),
6317 .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_rel64_hi12),
6318
6319 .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs32_lo12),
6320 .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs32_hi20),
6321 .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs64_lo20),
6322 .GOT64_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs64_hi12),
6323 },
6324 .SPARCV9 => switch (@"type".SPARC) {
6325 _,
6326 .NONE,
6327 .COPY,
6328 .GLOB_DAT,
6329 .JMP_SLOT,
6330 .RELATIVE,
6331 .IRELATIVE,
6332 => std.debug.panic("TODO: error for illegal or unsupported input relocation, {t}", .{@"type".SPARC}),
6333
6334 inline .WDISP22,
6335 .HI22,
6336 .@"22",
6337 .@"13",
6338 .LO10,
6339 .HIPLT22,
6340 .LOPLT10,
6341 .PCPLT22,
6342 .PCPLT10,
6343 .@"10",
6344 .@"11",
6345 .OLO10,
6346 .HH22,
6347 .HM10,
6348 .LM22,
6349 .PC_HH22,
6350 .PC_HM10,
6351 .PC_LM22,
6352 .WDISP16,
6353 .WDISP19,
6354 .@"7",
6355 .@"5",
6356 .@"6",
6357 .HIX22,
6358 .LOX10,
6359 .REGISTER,
6360 .TLS_GD_HI22,
6361 .TLS_GD_LO10,
6362 .TLS_IE_HI22,
6363 .TLS_IE_LO10,
6364 .TLS_DTPMOD32,
6365 .TLS_DTPMOD64,
6366 .H34,
6367 .WDISP10,
6368 => |t| @panic("TODO: " ++ @tagName(t)),
6369
6370 // Relocations targeting a symbol
6371 .@"8" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs8),
6372 .@"16" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs16),
6373 .@"32" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32),
6374 .DISP8 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel8),
6375 .DISP16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel16),
6376 .DISP32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32),
6377 .WDISP30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_wdisp30),
6378 .PC10 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_pc10),
6379 .PC22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_pc22),
6380 .WPLT30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_wplt30),
6381 .UA32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32),
6382 .PLT32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .pltabs32),
6383 .PCPLT32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .pltrel32),
6384 .@"64" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs64),
6385 .DISP64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64),
6386 .PLT64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .pltabs64),
6387 .H44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_h44),
6388 .M44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_m44),
6389 .L44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_l44),
6390 .UA64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs64),
6391 .UA16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs16),
6392 .TLS_GD_CALL, .TLS_LDM_CALL => try elf.addSymbolRelocAssumeCapacity(node, offset, try elf.externSymbolInner(.{
6393 .lib_name = null,
6394 .name = "__tls_get_addr",
6395 .type = .FUNC,
6396 }), addend, .sparc_wplt30),
6397 .SIZE32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .size32),
6398 .SIZE64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .size64),
6399
6400 // Relocations targeting a TLS symbol
6401 .TLS_LDO_HIX22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_ldo_hix22),
6402 .TLS_LDO_LOX10 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_ldo_lox10),
6403 .TLS_LE_HIX22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_le_hix22),
6404 .TLS_LE_LOX10 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .sparc_le_lox10),
6405 .TLS_DTPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .dtpoff32),
6406 .TLS_DTPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .dtpoff64),
6407 .TLS_TPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32),
6408 .TLS_TPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64),
6409 // We currently do no relaxation, so nothing to do for these.
6410 .TLS_GD_ADD,
6411 .TLS_LDM_ADD,
6412 .TLS_LDO_ADD,
6413 .TLS_IE_LD,
6414 .TLS_IE_LDX,
6415 .TLS_IE_ADD,
6416 => {},
6417
6418 // Relocations targeting a GOT entry
6419 .GOT10 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .sparc_10),
6420 .GOT13 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .sparc_13),
6421 .GOT22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .sparc_22),
6422 .TLS_LDM_HI22 => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .sparc_ldm_hi22),
6423 .TLS_LDM_LO10 => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .sparc_ldm_lo10),
6424 // These need similar handling to `R_X86_64_GOTOFF64`. No compiler seems to emit them though.
6425 .GOTDATA_HIX22 => @panic("TODO: R_SPARC_GOTDATA_HIX22"),
6426 .GOTDATA_LOX10 => @panic("TODO: R_SPARC_GOTDATA_LOX10"),
6427 .GOTDATA_OP_HIX22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .sparc_op_hix22),
6428 .GOTDATA_OP_LOX10 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .sparc_op_lox10),
6429 // We currently do no relaxation, so nothing to do for this one.
6430 .GOTDATA_OP => {},
59686431 },
59696432 },
59706433 }
......@@ -6008,29 +6471,46 @@ fn addSymbolRelocAssumeCapacity(
60086471 },
60096472 .abs64 => .@"64",
60106473 .abs32 => .@"32",
6474 .abs16 => unreachable,
6475 .abs8 => unreachable,
60116476 .abs32s => .@"32S",
60126477 .rel64 => .PC64,
60136478 .rel32 => .PC32,
6014 .pltrel64 => break :r .none,
6015 .pltrel32 => break :r .none,
6479 .rel16 => unreachable,
6480 .rel8 => unreachable,
6481 .pltabs64, .pltabs32, .pltrel64, .pltrel32 => break :r .none,
60166482 .dtpoff64 => .DTPOFF64,
60176483 .dtpoff32 => .DTPOFF32,
60186484 .tpoff64 => .TPOFF64,
60196485 .tpoff32 => .TPOFF32,
60206486 .size64 => .SIZE64,
60216487 .size32 => .SIZE32,
6022 .abs32_lo12,
6023 .rel32_hi20,
6024 .rel64_lo20,
6025 .rel64_hi12,
6026 .branch_rel18,
6027 .branch_rel23,
6028 .branch_rel28,
6029 .call_rel38,
6030 .tpoff32_lo12,
6031 .tpoff32_hi20,
6032 .tpoff64_lo20,
6033 .tpoff64_hi12,
6488
6489 .larch_abs32_lo12,
6490 .larch_rel32_hi20,
6491 .larch_rel64_lo20,
6492 .larch_rel64_hi12,
6493 .larch_branch_rel18,
6494 .larch_branch_rel23,
6495 .larch_branch_rel28,
6496 .larch_call_rel38,
6497 .larch_tpoff32_lo12,
6498 .larch_tpoff32_hi20,
6499 .larch_tpoff64_lo20,
6500 .larch_tpoff64_hi12,
6501 => unreachable,
6502
6503 .sparc_wdisp30,
6504 .sparc_pc10,
6505 .sparc_pc22,
6506 .sparc_wplt30,
6507 .sparc_h44,
6508 .sparc_m44,
6509 .sparc_l44,
6510 .sparc_ldo_hix22,
6511 .sparc_ldo_lox10,
6512 .sparc_le_hix22,
6513 .sparc_le_lox10,
60346514 => unreachable,
60356515 } },
60366516 .LOONGARCH => .{ .LOONGARCH = switch (@"type") {
......@@ -6041,26 +6521,95 @@ fn addSymbolRelocAssumeCapacity(
60416521 },
60426522 .abs64 => .@"64",
60436523 .abs32 => .@"32",
6044 .abs32s, .size64, .size32 => unreachable,
6524 .abs32s => unreachable,
6525 .abs16 => unreachable,
6526 .abs8 => unreachable,
60456527 .rel64 => .@"64_PCREL",
60466528 .rel32 => .@"32_PCREL",
6047 .pltrel64, .pltrel32 => break :r .none,
6529 .rel16 => unreachable,
6530 .rel8 => unreachable,
6531 .pltabs64, .pltabs32, .pltrel64, .pltrel32 => break :r .none,
60486532 .dtpoff64 => .TLS_DTPREL64,
60496533 .dtpoff32 => .TLS_DTPREL32,
60506534 .tpoff64 => .TLS_TPREL64,
60516535 .tpoff32 => .TLS_TPREL32,
6052 .abs32_lo12 => .PCALA_LO12,
6053 .rel32_hi20 => .PCALA_HI20,
6054 .rel64_lo20 => .PCALA64_LO20,
6055 .rel64_hi12 => .PCALA64_HI12,
6056 .branch_rel18 => .B16,
6057 .branch_rel23 => .B21,
6058 .branch_rel28 => .B26,
6059 .call_rel38 => .CALL36,
6060 .tpoff32_lo12 => .TLS_LE_LO12,
6061 .tpoff32_hi20 => .TLS_LE_HI20,
6062 .tpoff64_lo20 => .TLS_LE64_LO20,
6063 .tpoff64_hi12 => .TLS_LE64_HI12,
6536 .size64 => unreachable,
6537 .size32 => unreachable,
6538
6539 .larch_abs32_lo12 => .PCALA_LO12,
6540 .larch_rel32_hi20 => .PCALA_HI20,
6541 .larch_rel64_lo20 => .PCALA64_LO20,
6542 .larch_rel64_hi12 => .PCALA64_HI12,
6543 .larch_branch_rel18 => .B16,
6544 .larch_branch_rel23 => .B21,
6545 .larch_branch_rel28 => .B26,
6546 .larch_call_rel38 => .CALL36,
6547 .larch_tpoff32_lo12 => .TLS_LE_LO12,
6548 .larch_tpoff32_hi20 => .TLS_LE_HI20,
6549 .larch_tpoff64_lo20 => .TLS_LE64_LO20,
6550 .larch_tpoff64_hi12 => .TLS_LE64_HI12,
6551
6552 .sparc_wdisp30,
6553 .sparc_pc10,
6554 .sparc_pc22,
6555 .sparc_wplt30,
6556 .sparc_h44,
6557 .sparc_m44,
6558 .sparc_l44,
6559 .sparc_ldo_hix22,
6560 .sparc_ldo_lox10,
6561 .sparc_le_hix22,
6562 .sparc_le_lox10,
6563 => unreachable,
6564 } },
6565 .SPARCV9 => .{ .SPARC = switch (@"type") {
6566 .write_rela => unreachable,
6567 .dsorel64, .dsorel32 => {
6568 assert(target.unwrap() == .local);
6569 break :r .none;
6570 },
6571 .abs64 => .@"64",
6572 .abs32 => .@"32",
6573 .abs32s => unreachable,
6574 .abs16 => .@"16",
6575 .abs8 => .@"8",
6576 .rel64 => .DISP64,
6577 .rel32 => .DISP32,
6578 .rel16 => .DISP16,
6579 .rel8 => .DISP8,
6580 .pltabs64, .pltabs32, .pltrel64, .pltrel32 => break :r .none,
6581 .dtpoff64 => .TLS_DTPOFF64,
6582 .dtpoff32 => .TLS_DTPOFF32,
6583 .tpoff64 => .TLS_TPOFF64,
6584 .tpoff32 => .TLS_TPOFF32,
6585 .size64 => .SIZE64,
6586 .size32 => .SIZE32,
6587
6588 .larch_abs32_lo12,
6589 .larch_rel32_hi20,
6590 .larch_rel64_lo20,
6591 .larch_rel64_hi12,
6592 .larch_branch_rel18,
6593 .larch_branch_rel23,
6594 .larch_branch_rel28,
6595 .larch_call_rel38,
6596 .larch_tpoff32_lo12,
6597 .larch_tpoff32_hi20,
6598 .larch_tpoff64_lo20,
6599 .larch_tpoff64_hi12,
6600 => unreachable,
6601
6602 .sparc_wdisp30 => .WDISP30,
6603 .sparc_pc10 => .PC10,
6604 .sparc_pc22 => .PC22,
6605 .sparc_wplt30 => .WPLT30,
6606 .sparc_h44 => .H44,
6607 .sparc_m44 => .M44,
6608 .sparc_l44 => .L44,
6609 .sparc_ldo_hix22 => .TLS_LDO_HIX22,
6610 .sparc_ldo_lox10 => .TLS_LDO_LOX10,
6611 .sparc_le_hix22 => .TLS_LE_HIX22,
6612 .sparc_le_lox10 => .TLS_LE_LOX10,
60646613 } },
60656614 };
60666615
......@@ -6221,8 +6770,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
62216770 }
62226771 const reloc_type: MachineRelocType = switch (elf.ehdrField(.machine)) {
62236772 else => |machine| @panic(@tagName(machine)),
6224 .X86_64 => .{ .X86_64 = .TPOFF64 },
62256773 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },
6774 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_TPOFF64 else .TLS_TPOFF32 },
6775 .X86_64 => .{ .X86_64 = .TPOFF64 },
62266776 };
62276777 break :val switch (sym_id.unwrap()) {
62286778 // For global symbols, just target the right dynsym with no addend.
......@@ -6270,8 +6820,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
62706820 .dynamic => .{ .reloc = .{
62716821 .type = switch (elf.ehdrField(.machine)) {
62726822 else => |machine| @panic(@tagName(machine)),
6273 .X86_64 => .{ .X86_64 = .DTPMOD64 },
62746823 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
6824 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
6825 .X86_64 => .{ .X86_64 = .DTPMOD64 },
62756826 },
62766827 .dynsym_index = switch (elf.classifySymbolValue(sym)) {
62776828 .static, .static_relative => 0,
......@@ -6288,8 +6839,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
62886839 .dynamic => .{ .reloc = .{
62896840 .type = switch (elf.ehdrField(.machine)) {
62906841 else => |machine| @panic(@tagName(machine)),
6291 .X86_64 => .{ .X86_64 = .DTPMOD64 },
62926842 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
6843 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
6844 .X86_64 => .{ .X86_64 = .DTPMOD64 },
62936845 },
62946846 .dynsym_index = 0,
62956847 .addend = 0,
......@@ -7341,6 +7893,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
73417893 },
73427894 }
73437895 },
7896 .SPARCV9 => switch (which) {
7897 .plt => {
7898 // Update the offsets of the relocation entries in `.rela.plt`.
7899 const rela_plt_shndx = elf.shndx.rela_plt;
7900 for (0..elf.plt.count()) |plt_index| {
7901 if (elf.pltEntryIsDead(plt_index)) continue;
7902 rela_plt_shndx.relaAdjustOffset(elf, @enumFromInt(plt_index), old_addr, addr);
7903 }
7904 },
7905 .plt_sec, .got_plt => unreachable,
7906 },
73447907 }
73457908}
73467909
src/link/sparc.zig created+197
......@@ -0,0 +1,197 @@
1const std = @import("std");
2
3/// Calculation operands:
4///
5/// * `A`: relocation addend
6/// * `G`: symbol GOT slot offset
7/// * `GOT`: GOT base address (`_GLOBAL_OFFSET_TABLE_` value)
8/// * `L`: symbol PLT slot address
9/// * `O`: secondary relocation addend
10/// * `P`: relocation address
11/// * `S`: symbol value
12/// * `Z`: symbol size
13///
14/// Field semantics:
15///
16/// * `T-*`: truncate (don't check for overflow)
17/// * `V-*`: verify (check for overflow)
18pub const reloc = struct {
19 /// R_SPARC_8 (V-byte8) = S + A
20 /// R_SPARC_DISP8 (V-byte8) = S + A - P
21 pub const Byte8 = packed struct(u8) {
22 byte8: u8,
23 };
24
25 /// R_SPARC_16 (V-half16) = S + A
26 /// R_SPARC_DISP16 (V-half16) = S + A - P
27 /// R_SPARC_UA16 (V-half16) = S + A
28 pub const Half16 = packed struct(u16) {
29 half16: u16,
30 };
31
32 /// R_SPARC_32 (V-word32) = S + A
33 /// R_SPARC_GLOB_DAT (V-word32) = S + A [32-bit only]
34 /// R_SPARC_UA32 (V-word32) = S + A
35 /// R_SPARC_PCPLT32 (V-word32) = L + A - P
36 /// R_SPARC_REGISTER (V-word32) = S + A [32-bit only]
37 /// R_SPARC_TLS_DTPMOD32 (V-word32) = @dtpmod(S + A)
38 /// R_SPARC_TLS_DTPOFF32 (V-word32) = @dtpoff(S + A)
39 /// R_SPARC_TLS_TPOFF32 (V-word32) = @tpoff(S + A)
40 /// R_SPARC_SIZE32 (V-word32) = Z + A
41 pub const Word32 = packed struct(u32) {
42 word32: u32,
43 };
44
45 /// R_SPARC_GLOB_DAT (V-word64) = S + A [64-bit only]
46 /// R_SPARC_64 (V-word64) = S + A
47 /// R_SPARC_DISP64 (V-word64) = S + A - P
48 /// R_SPARC_PLT64 (V-word64) = L + A
49 /// R_SPARC_REGISTER (V-word64) = S + A [64-bit only]
50 /// R_SPARC_UA64 (V-word64) = S + A
51 /// R_SPARC_TLS_DTPMOD64 (V-word64) = @dtpmod(S + A)
52 /// R_SPARC_TLS_DTPOFF64 (V-word64) = @dtpoff(S + A)
53 /// R_SPARC_TLS_TPOFF64 (V-word64) = @tpoff(S + A)
54 /// R_SPARC_SIZE64 (V-word64) = Z + A
55 pub const Word64 = packed struct(u64) {
56 word64: u64,
57 };
58
59 /// R_SPARC_5 (V-imm5) = S + A
60 pub const Imm5 = packed struct(u32) {
61 imm5: u5,
62 b5_31: u27,
63 };
64
65 /// R_SPARC_6 (V-imm6) = S + A
66 pub const Imm6 = packed struct(u32) {
67 imm6: u6,
68 b6_31: u26,
69 };
70
71 /// R_SPARC_7 (V-imm7) = S + A
72 pub const Imm7 = packed struct(u32) {
73 imm7: u7,
74 b7_31: u25,
75 };
76
77 /// R_SPARC_M44 (T-imm10) = ((S + A) >> 12) & 0x3ff
78 pub const Imm10 = packed struct(u32) {
79 imm10: u10,
80 b10_31: u22,
81 };
82
83 /// R_SPARC_10 (V-simm10) = S + A
84 pub const Simm10 = packed struct(u32) {
85 simm10: u10,
86 b10_31: u22,
87 };
88
89 /// R_SPARC_11 (V-simm11) = S + A
90 pub const Simm11 = packed struct(u32) {
91 simm11: u11,
92 b11_31: u21,
93 };
94
95 /// R_SPARC_L44 (T-imm13) = (S + A) & 0xfff
96 /// R_SPARC_GOTDATA_LOX10 (T-imm13) = ((S + A - GOT) & 0x3ff) | (((S + A - GOT) >> 31) & 0x1c00)
97 /// R_SPARC_GOTDATA_OP_LOX10 (T-imm13) = (G & 0x3ff) | ((G >> 31) & 0x1c00)
98 pub const Imm13 = packed struct(u32) {
99 imm13: u13,
100 b13_31: u19,
101 };
102
103 /// R_SPARC_13 (V-simm13) = S + A
104 /// R_SPARC_LO10 (T-simm13) = (S + A) & 0x3ff
105 /// R_SPARC_GOT10 (T-simm13) = G & 0x3ff
106 /// R_SPARC_GOT13 (V-simm13) = G
107 /// R_SPARC_PC10 (T-simm13) = (S + A - P) & 0x3ff
108 /// R_SPARC_LOPLT10 (T-simm13) = (L + A) & 0x3ff
109 /// R_SPARC_PCPLT10 (V-simm13) = (L + A - P) & 0x3ff
110 /// R_SPARC_OLO10 (V-simm13) = ((S + A) & 0x3ff) + O
111 /// R_SPARC_HM10 (T-simm13) = ((S + A) >> 32) & 0x3ff
112 /// R_SPARC_PC_HM10 (T-simm13) = ((S + A - P) >> 32) & 0x3ff
113 /// R_SPARC_LOX10 (T-simm13) = ((S + A) & 0x3ff) | 0x1c00
114 /// R_SPARC_TLS_GD_LO10 (T-simm13) = @dtlndx(S + A) & 0x3ff
115 /// R_SPARC_TLS_LDM_LO10 (T-simm13) = @tmndx(S + A) & 0x3ff
116 /// R_SPARC_TLS_LDO_LOX10 (T-simm13) = @dtpoff(S + A) & 0x3ff
117 /// R_SPARC_TLS_IE_LO10 (T-simm13) = @got(@tpoff(S + A)) & 0x3ff
118 /// R_SPARC_TLS_LE_LOX10 (T-simm13) = (@tpoff(S + A) & 0x3ff) | 0x1c00
119 pub const Simm13 = packed struct(u32) {
120 simm13: u13,
121 b13_31: u19,
122 };
123
124 /// R_SPARC_HI22 (T-imm22) = (S + A) >> 10 [32-bit only]
125 /// R_SPARC_HI22 (V-imm22) = (S + A) >> 10 [64-bit only]
126 /// R_SPARC_22 (V-imm22) = S + A
127 /// R_SPARC_HIPLT22 (T-imm22) = (L + A) >> 10
128 /// R_SPARC_HH22 (V-imm22) = (S + A) >> 42
129 /// R_SPARC_LM22 (T-imm22) = (S + A) >> 10
130 /// R_SPARC_PC_HH22 (V-imm22) = (S + A - P) >> 42
131 /// R_SPARC_PC_LM22 (T-imm22) = (S + A - P) >> 10
132 /// R_SPARC_HIX22 (V-imm22) = ((S + A) ^ 0xffffffffffffffff) >> 10
133 /// R_SPARC_H44 (V-imm22) = (S + A) >> 22
134 /// R_SPARC_TLS_LE_HIX22 (T-imm22) = (@tpoff(S + A) ^ 0xffffffffffffffff) >> 10
135 /// R_SPARC_GOTDATA_HIX22 (V-imm22) = ((S + A - GOT) >> 10) ^ ((S + A - GOT) >> 31)
136 /// R_SPARC_GOTDATA_OP_HIX22 (T-imm22) = (G >> 10) ^ (G >> 31)
137 /// R_SPARC_H34 (V-imm22) = (S + A) >> 12
138 pub const Imm22 = packed struct(u32) {
139 imm22: u22,
140 b22_31: u10,
141 };
142
143 /// R_SPARC_GOT22 (T-simm22) = G >> 10
144 /// R_SPARC_TLS_GD_HI22 (T-simm22) = @dtlndx(S + A) >> 10
145 /// R_SPARC_TLS_LDM_HI22 (T-simm22) = @tmndx(S + A) >> 10
146 /// R_SPARC_TLS_LDO_HIX22 (T-simm22) = @dtpoff(S + A) >> 10
147 /// R_SPARC_TLS_IE_HI22 (T-simm22) = @got(@tpoff(S + A)) >> 10
148 pub const Simm22 = packed struct(u32) {
149 simm22: u22,
150 b22_31: u10,
151 };
152
153 /// R_SPARC_WDISP19 (V-disp19) = (S + A - P) >> 2
154 pub const Disp19 = packed struct(u32) {
155 disp19: u19,
156 b19_31: u13,
157 };
158
159 /// R_SPARC_WDISP22 (V-disp22) = (S + A - P) >> 2
160 /// R_SPARC_PC22 (V-disp22) = (S + A - P) >> 10
161 /// R_SPARC_PCPLT22 (V-disp22) = (L + A - P) >> 10
162 pub const Disp22 = packed struct(u32) {
163 disp22: u22,
164 b22_31: u10,
165 };
166
167 /// R_SPARC_WDISP30 (V-disp30) = (S + A - P) >> 2
168 /// R_SPARC_WPLT30 (V-disp30) = (L + A - P) >> 2
169 /// R_SPARC_TLS_GD_CALL (V-disp30) = (L + A - P) >> 2
170 /// R_SPARC_TLS_LDM_CALL (V-disp30) = (L + A - P) >> 2
171 pub const Disp30 = packed struct(u32) {
172 disp30: u30,
173 b30_31: u2,
174 };
175
176 /// R_SPARC_DISP32 (V-disp32) = S + A - P
177 pub const Disp32 = packed struct(u32) {
178 disp32: u32,
179 };
180
181 /// R_SPARC_WDISP10 (V-d2/disp8) = (S + A - P) >> 2
182 pub const D2Disp8 = packed struct(u32) {
183 b0_3: u4,
184 disp8: u8,
185 b12_17: u6,
186 d2: u2,
187 b20_31: u12,
188 };
189
190 /// R_SPARC_WDISP16 (V-d2/disp14) = (S + A - P) >> 2
191 pub const D2Disp14 = packed struct(u32) {
192 disp14: u14,
193 b14_19: u6,
194 d2: u2,
195 b22_31: u10,
196 };
197};