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) {...@@ -1644,6 +1644,14 @@ pub const CLASS = enum(u8) {
16441644
1645 pub const NUM = @typeInfo(CLASS).@"enum".field_names.len;1645 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
1647 pub fn ElfN(comptime class: CLASS) type {1655 pub fn ElfN(comptime class: CLASS) type {
1648 return switch (class) {1656 return switch (class) {
1649 .NONE, _ => comptime unreachable,1657 .NONE, _ => comptime unreachable,
...@@ -1668,6 +1676,14 @@ pub const DATA = enum(u8) {...@@ -1668,6 +1676,14 @@ pub const DATA = enum(u8) {
1668 _,1676 _,
16691677
1670 pub const NUM = @typeInfo(DATA).@"enum".field_names.len;1678 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 }
1671};1687};
16721688
1673pub const OSABI = enum(u8) {1689pub const OSABI = enum(u8) {
...@@ -3136,6 +3152,99 @@ pub const R_LARCH = enum(u32) {...@@ -3136,6 +3152,99 @@ pub const R_LARCH = enum(u32) {
3136 _,3152 _,
3137};3153};
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
3139pub const ar_hdr = extern struct {3248pub const ar_hdr = extern struct {
3140 /// Member file name, sometimes / terminated.3249 /// Member file name, sometimes / terminated.
3141 ar_name: [16]u8,3250 ar_name: [16]u8,
...@@ -3281,3 +3390,35 @@ pub const loongarch = struct {...@@ -3281,3 +3390,35 @@ pub const loongarch = struct {
3281 pub const AbiExtension = enum(u3) { base = 0, _ };3390 pub const AbiExtension = enum(u3) { base = 0, _ };
3282 };3391 };
3283};3392};
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");...@@ -26,12 +26,13 @@ const target_util = @import("target.zig");
26const codegen = @import("codegen.zig");26const codegen = @import("codegen.zig");
27const crash_report = @import("crash_report.zig");27const crash_report = @import("crash_report.zig");
2828
29pub const aarch64 = @import("link/aarch64.zig");
30pub const LdScript = @import("link/LdScript.zig");29pub const LdScript = @import("link/LdScript.zig");
31pub const Queue = @import("link/Queue.zig");30pub const Queue = @import("link/Queue.zig");
32pub const ConstPool = @import("link/ConstPool.zig");31pub const ConstPool = @import("link/ConstPool.zig");
3332
33pub const aarch64 = @import("link/aarch64.zig");
34pub const loongarch = @import("link/loongarch.zig");34pub const loongarch = @import("link/loongarch.zig");
35pub const sparc = @import("link/sparc.zig");
3536
36pub const Error = Allocator.Error || Io.Cancelable || error{37pub const Error = Allocator.Error || Io.Cancelable || error{
37 /// An error message has already been stored in persistent state on `Compilation` or `Zcu`, for38 /// 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),...@@ -28,8 +28,10 @@ shdrs: std.ArrayList(Section),
28phdrs: std.ArrayList(MappedFile.Node.Index),28phdrs: std.ArrayList(MappedFile.Node.Index),
29shndx: struct {29shndx: struct {
30 got: Section.Index,30 got: Section.Index,
31 /// Always `.UNDEF` on some targets (e.g. SPARC).
31 got_plt: Section.Index,32 got_plt: Section.Index,
32 plt: Section.Index,33 plt: Section.Index,
34 /// Only created for x86 targets; `.UNDEF` everywhere else.
33 plt_sec: Section.Index,35 plt_sec: Section.Index,
34 dynsym: Section.Index,36 dynsym: Section.Index,
35 dynstr: Section.Index,37 dynstr: Section.Index,
...@@ -777,18 +779,26 @@ const GotReloc = struct {...@@ -777,18 +779,26 @@ const GotReloc = struct {
777 };779 };
778780
779 const Type = enum(u8) {781 const Type = enum(u8) {
780 offset64,
781 offset32,782 offset32,
782 rel64,783 offset64,
783 rel32,784 rel32,
785 rel64,
784786
785 rel32_hi20,787 larch_rel32_hi20,
786 rel64_lo20,788 larch_rel64_lo20,
787 rel64_hi12,789 larch_rel64_hi12,
788 abs32_lo12,790 larch_abs32_lo12,
789 abs32_hi20,791 larch_abs32_hi20,
790 abs64_lo20,792 larch_abs64_lo20,
791 abs64_hi12,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,
792 };802 };
793803
794 const Index = enum(u32) {804 const Index = enum(u32) {
...@@ -857,51 +867,96 @@ const GotReloc = struct {...@@ -857,51 +867,96 @@ const GotReloc = struct {
857 @intCast(@as(i64, @bitCast(got_vaddr +% got_offset +% addend -% dest_vaddr))),867 @intCast(@as(i64, @bitCast(got_vaddr +% got_offset +% addend -% dest_vaddr))),
858 target_endian,868 target_endian,
859 ),869 ),
860 .rel32_hi20 => {870
871 .larch_rel32_hi20 => {
861 assert(elf.ehdrField(.machine) == .LOONGARCH);872 assert(elf.ehdrField(.machine) == .LOONGARCH);
862 const target_value = got_vaddr +% got_offset +% addend;873 const target_value = got_vaddr +% got_offset +% addend;
863 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr));874 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr));
864 },875 },
865 .rel64_lo20 => {876 .larch_rel64_lo20 => {
866 assert(elf.ehdrField(.machine) == .LOONGARCH);877 assert(elf.ehdrField(.machine) == .LOONGARCH);
867 const target_value = got_vaddr +% got_offset +% addend;878 const target_value = got_vaddr +% got_offset +% addend;
868 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr));879 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr));
869 },880 },
870 .rel64_hi12 => {881 .larch_rel64_hi12 => {
871 assert(elf.ehdrField(.machine) == .LOONGARCH);882 assert(elf.ehdrField(.machine) == .LOONGARCH);
872 const target_value = got_vaddr +% got_offset +% addend;883 const target_value = got_vaddr +% got_offset +% addend;
873 link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr));884 link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr));
874 },885 },
875 .abs32_lo12 => {886 .larch_abs32_lo12 => {
876 assert(elf.ehdrField(.machine) == .LOONGARCH);887 assert(elf.ehdrField(.machine) == .LOONGARCH);
877 const target_value = got_vaddr +% got_offset +% addend;888 const target_value = got_vaddr +% got_offset +% addend;
878 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));889 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));
879 },890 },
880 .abs32_hi20 => {891 .larch_abs32_hi20 => {
881 assert(elf.ehdrField(.machine) == .LOONGARCH);892 assert(elf.ehdrField(.machine) == .LOONGARCH);
882 const target_value = got_vaddr +% got_offset +% addend;893 const target_value = got_vaddr +% got_offset +% addend;
883 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12));894 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12));
884 },895 },
885 .abs64_lo20 => {896 .larch_abs64_lo20 => {
886 assert(elf.ehdrField(.machine) == .LOONGARCH);897 assert(elf.ehdrField(.machine) == .LOONGARCH);
887 const target_value = got_vaddr +% got_offset +% addend;898 const target_value = got_vaddr +% got_offset +% addend;
888 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32));899 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32));
889 },900 },
890 .abs64_hi12 => {901 .larch_abs64_hi12 => {
891 assert(elf.ehdrField(.machine) == .LOONGARCH);902 assert(elf.ehdrField(.machine) == .LOONGARCH);
892 const target_value = got_vaddr +% got_offset +% addend;903 const target_value = got_vaddr +% got_offset +% addend;
893 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52));904 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52));
894 },905 },
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 },
895 }949 }
896 }950 }
897};951};
898952
899pub const MachineRelocType = union {953pub const MachineRelocType = union {
900 X86_64: std.elf.R_X86_64,
901 AARCH64: std.elf.R_AARCH64,954 AARCH64: std.elf.R_AARCH64,
902 LOONGARCH: std.elf.R_LARCH,955 LOONGARCH: std.elf.R_LARCH,
903 RISCV: std.elf.R_RISCV,
904 PPC64: std.elf.R_PPC64,956 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
906 pub fn none(elf: *Elf) MachineRelocType {961 pub fn none(elf: *Elf) MachineRelocType {
907 return switch (elf.ehdrField(.machine)) {962 return switch (elf.ehdrField(.machine)) {
...@@ -910,6 +965,7 @@ pub const MachineRelocType = union {...@@ -910,6 +965,7 @@ pub const MachineRelocType = union {
910 .LOONGARCH => .{ .LOONGARCH = .NONE },965 .LOONGARCH => .{ .LOONGARCH = .NONE },
911 .PPC64 => .{ .PPC64 = .NONE },966 .PPC64 => .{ .PPC64 = .NONE },
912 .RISCV => .{ .RISCV = .NONE },967 .RISCV => .{ .RISCV = .NONE },
968 .SPARCV9 => .{ .SPARC = .NONE },
913 .X86_64 => .{ .X86_64 = .NONE },969 .X86_64 => .{ .X86_64 = .NONE },
914 };970 };
915 }971 }
...@@ -920,6 +976,7 @@ pub const MachineRelocType = union {...@@ -920,6 +976,7 @@ pub const MachineRelocType = union {
920 .LOONGARCH => .{ .LOONGARCH = .COPY },976 .LOONGARCH => .{ .LOONGARCH = .COPY },
921 .PPC64 => .{ .PPC64 = .COPY },977 .PPC64 => .{ .PPC64 = .COPY },
922 .RISCV => .{ .RISCV = .COPY },978 .RISCV => .{ .RISCV = .COPY },
979 .SPARCV9 => .{ .SPARC = .COPY },
923 .X86_64 => .{ .X86_64 = .COPY },980 .X86_64 => .{ .X86_64 = .COPY },
924 };981 };
925 }982 }
...@@ -930,43 +987,57 @@ pub const MachineRelocType = union {...@@ -930,43 +987,57 @@ pub const MachineRelocType = union {
930 .LOONGARCH => .{ .LOONGARCH = .RELATIVE },987 .LOONGARCH => .{ .LOONGARCH = .RELATIVE },
931 .PPC64 => .{ .PPC64 = .RELATIVE },988 .PPC64 => .{ .PPC64 = .RELATIVE },
932 .RISCV => .{ .RISCV = .RELATIVE },989 .RISCV => .{ .RISCV = .RELATIVE },
990 .SPARCV9 => .{ .SPARC = .RELATIVE },
933 .X86_64 => .{ .X86_64 = .RELATIVE },991 .X86_64 => .{ .X86_64 = .RELATIVE },
934 };992 };
935 }993 }
936 pub fn jumpSlot(elf: *Elf) MachineRelocType {994 pub fn jumpSlot(elf: *Elf) MachineRelocType {
937 return switch (elf.ehdrField(.machine)) {995 return switch (elf.ehdrField(.machine)) {
938 else => unreachable,996 else => unreachable,
939 .X86_64 => .{ .X86_64 = .JUMP_SLOT },997 .AARCH64 => .{ .AARCH64 = .JUMP_SLOT },
940 .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT },998 .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 },
941 };1003 };
942 }1004 }
943 pub fn globDat(elf: *Elf) MachineRelocType {1005 pub fn globDat(elf: *Elf) MachineRelocType {
944 return switch (elf.ehdrField(.machine)) {1006 return switch (elf.ehdrField(.machine)) {
945 else => unreachable,1007 else => unreachable,
946 .X86_64 => .{ .X86_64 = .GLOB_DAT },1008 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
947 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },1009 .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 },
948 };1014 };
949 }1015 }
950 pub fn dtpOffAddr(elf: *Elf) MachineRelocType {1016 pub fn dtpOffAddr(elf: *Elf) MachineRelocType {
951 return switch (elf.ehdrField(.machine)) {1017 return switch (elf.ehdrField(.machine)) {
952 else => unreachable,1018 else => unreachable,
953 .X86_64 => .{ .X86_64 = .DTPOFF64 },
954 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },1019 .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 },
955 };1024 };
956 }1025 }
957 pub fn absAddr(elf: *Elf) MachineRelocType {1026 pub fn absAddr(elf: *Elf) MachineRelocType {
958 return switch (elf.ehdrField(.machine)) {1027 return switch (elf.ehdrField(.machine)) {
959 else => unreachable,1028 else => unreachable,
960 .AARCH64 => .{ .AARCH64 = .ABS64 },1029 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 },
961 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },1030 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
962 .PPC64 => .{ .PPC64 = .ADDR64 },1031 .PPC64 => .{ .PPC64 = .ADDR64 },
963 .RISCV => .{ .RISCV = .@"64" },1032 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
964 .X86_64 => .{ .X86_64 = .@"64" },1033 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" },
1034 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" },
965 };1035 };
966 }1036 }
967 pub fn sizeAddr(elf: *Elf) MachineRelocType {1037 pub fn sizeAddr(elf: *Elf) MachineRelocType {
968 return switch (elf.ehdrField(.machine)) {1038 return switch (elf.ehdrField(.machine)) {
969 else => unreachable,1039 else => unreachable,
1040 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .SIZE64 else .SIZE32 },
970 .X86_64 => .{ .X86_64 = .SIZE64 },1041 .X86_64 => .{ .X86_64 = .SIZE64 },
971 };1042 };
972 }1043 }
...@@ -974,6 +1045,7 @@ pub const MachineRelocType = union {...@@ -974,6 +1045,7 @@ pub const MachineRelocType = union {
974 pub fn wrap(int: u32, elf: *Elf) MachineRelocType {1045 pub fn wrap(int: u32, elf: *Elf) MachineRelocType {
975 return switch (elf.ehdrField(.machine)) {1046 return switch (elf.ehdrField(.machine)) {
976 else => unreachable,1047 else => unreachable,
1048 .SPARCV9 => .{ .SPARC = @enumFromInt(int) },
977 inline .AARCH64,1049 inline .AARCH64,
978 .LOONGARCH,1050 .LOONGARCH,
979 .PPC64,1051 .PPC64,
...@@ -985,6 +1057,7 @@ pub const MachineRelocType = union {...@@ -985,6 +1057,7 @@ pub const MachineRelocType = union {
985 pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 {1057 pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 {
986 return switch (elf.ehdrField(.machine)) {1058 return switch (elf.ehdrField(.machine)) {
987 else => unreachable,1059 else => unreachable,
1060 .SPARCV9 => @intFromEnum(rt.SPARC),
988 inline .AARCH64,1061 inline .AARCH64,
989 .LOONGARCH,1062 .LOONGARCH,
990 .PPC64,1063 .PPC64,
...@@ -1073,37 +1146,67 @@ const SymbolReloc = struct {...@@ -1073,37 +1146,67 @@ const SymbolReloc = struct {
1073 /// This is only used targeting local symbols so can always be statically resolved.1146 /// This is only used targeting local symbols so can always be statically resolved.
1074 dsorel32,1147 dsorel32,
10751148
1076 abs64,1149 abs8,
1150 abs16,
1077 abs32,1151 abs32,
1078 abs32s,1152 abs32s,
1079 rel64,1153 abs64,
1154 rel8,
1155 rel16,
1080 rel32,1156 rel32,
1081 pltrel64,1157 rel64,
1158 pltabs32,
1159 pltabs64,
1082 pltrel32,1160 pltrel32,
1083 dtpoff64,1161 pltrel64,
1084 dtpoff32,1162 dtpoff32,
1085 tpoff64,1163 dtpoff64,
1086 tpoff32,1164 tpoff32,
1087 size64,1165 tpoff64,
1088 size32,1166 size32,
1167 size64,
10891168
1090 abs32_lo12,1169 larch_abs32_lo12,
1091 rel32_hi20,1170 larch_rel32_hi20,
1092 rel64_lo20,1171 larch_rel64_lo20,
1093 rel64_hi12,1172 larch_rel64_hi12,
1094 branch_rel18,1173 larch_branch_rel18,
1095 branch_rel23,1174 larch_branch_rel23,
1096 branch_rel28,1175 larch_branch_rel28,
1097 call_rel38,1176 larch_call_rel38,
1098 tpoff32_lo12,1177 larch_tpoff32_lo12,
1099 tpoff32_hi20,1178 larch_tpoff32_hi20,
1100 tpoff64_lo20,1179 larch_tpoff64_lo20,
1101 tpoff64_hi12,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
1103 fn dependsOnTlsSize(t: SymbolReloc.Type) bool {1194 fn dependsOnTlsSize(t: SymbolReloc.Type) bool {
1104 return switch (t) {1195 return switch (t) {
1105 .tpoff32, .tpoff64 => true,1196 .tpoff32,
1106 .tpoff32_lo12, .tpoff32_hi20, .tpoff64_lo20, .tpoff64_hi12 => true,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
1107 else => false,1210 else => false,
1108 };1211 };
1109 }1212 }
...@@ -1111,8 +1214,18 @@ const SymbolReloc = struct {...@@ -1111,8 +1214,18 @@ const SymbolReloc = struct {
1111 fn isAbsAddr(t: SymbolReloc.Type, elf: *const Elf) bool {1214 fn isAbsAddr(t: SymbolReloc.Type, elf: *const Elf) bool {
1112 return switch (elf.identClass()) {1215 return switch (elf.identClass()) {
1113 .NONE, _ => unreachable,1216 .NONE, _ => unreachable,
1114 .@"32" => t == .abs32,1217 .@"32" => switch (t) {
1115 .@"64" => t == .abs64,1218 .abs32,
1219 .pltabs32,
1220 => true,
1221 else => false,
1222 },
1223 .@"64" => switch (t) {
1224 .abs64,
1225 .pltabs64,
1226 => true,
1227 else => false,
1228 },
1116 };1229 };
1117 }1230 }
1118 };1231 };
...@@ -1131,11 +1244,31 @@ const SymbolReloc = struct {...@@ -1131,11 +1244,31 @@ const SymbolReloc = struct {
1131 .static => unreachable,1244 .static => unreachable,
1132 .dynamic => return, // the relocation happens at runtime1245 .dynamic => return, // the relocation happens at runtime
1133 .static_relative => {1246 .static_relative => {
1134 assert(reloc.type.isAbsAddr(elf));
1135 // We have emitted an R_*_RELATIVE relocation to help lower an abs32/abs64 reloc.1247 // We have emitted an R_*_RELATIVE relocation to help lower an abs32/abs64 reloc.
1136 // This is a simplified version of the general relocation handling logic, where we1248 // This is a simplified version of the general relocation handling logic, where we
1137 // know we're using '.abs64' or '.abs32' (matching the ELF ident class).1249 // 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 };
1139 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, value);1272 elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, value);
1140 return;1273 return;
1141 },1274 },
...@@ -1182,6 +1315,13 @@ const SymbolReloc = struct {...@@ -1182,6 +1315,13 @@ const SymbolReloc = struct {
1182 @intCast(@as(i64, @bitCast(target_value))),1315 @intCast(@as(i64, @bitCast(target_value))),
1183 target_endian,1316 target_endian,
1184 ),1317 ),
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),
1185 .rel64 => std.mem.writeInt(1325 .rel64 => std.mem.writeInt(
1186 i64,1326 i64,
1187 dest_slice[0..8],1327 dest_slice[0..8],
...@@ -1194,17 +1334,65 @@ const SymbolReloc = struct {...@@ -1194,17 +1334,65 @@ const SymbolReloc = struct {
1194 @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))),1334 @intCast(@as(i64, @bitCast(target_value -% dest_vaddr))),
1195 target_endian,1335 target_endian,
1196 ),1336 ),
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 },
1197 .pltrel64 => {1384 .pltrel64 => {
1198 const plt_index = switch (reloc.target.unwrap()) {1385 const plt_index = switch (reloc.target.unwrap()) {
1199 .local => continue :type .rel64,1386 .local => continue :type .rel64,
1200 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel64,1387 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel64,
1201 };1388 };
1202 if (elf.pltEntryIsDead(plt_index)) continue :type .rel64;1389 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)) {
1204 else => |machine| @panic(@tagName(machine)),1391 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 },
1206 };1394 };
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;
1208 std.mem.writeInt(1396 std.mem.writeInt(
1209 i64,1397 i64,
1210 dest_slice[0..8],1398 dest_slice[0..8],
...@@ -1218,11 +1406,12 @@ const SymbolReloc = struct {...@@ -1218,11 +1406,12 @@ const SymbolReloc = struct {
1218 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel32,1406 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel32,
1219 };1407 };
1220 if (elf.pltEntryIsDead(plt_index)) continue :type .rel32;1408 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)) {
1222 else => |machine| @panic(@tagName(machine)),1410 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 },
1224 };1413 };
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;
1226 std.mem.writeInt(1415 std.mem.writeInt(
1227 i32,1416 i32,
1228 dest_slice[0..4],1417 dest_slice[0..4],
...@@ -1286,42 +1475,43 @@ const SymbolReloc = struct {...@@ -1286,42 +1475,43 @@ const SymbolReloc = struct {
1286 target_endian,1475 target_endian,
1287 );1476 );
1288 },1477 },
1289 .abs32_lo12 => {1478
1479 .larch_abs32_lo12 => {
1290 assert(elf.ehdrField(.machine) == .LOONGARCH);1480 assert(elf.ehdrField(.machine) == .LOONGARCH);
1291 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));1481 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));
1292 },1482 },
1293 .rel32_hi20 => {1483 .larch_rel32_hi20 => {
1294 assert(elf.ehdrField(.machine) == .LOONGARCH);1484 assert(elf.ehdrField(.machine) == .LOONGARCH);
1295 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr));1485 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr));
1296 },1486 },
1297 .rel64_lo20 => {1487 .larch_rel64_lo20 => {
1298 assert(elf.ehdrField(.machine) == .LOONGARCH);1488 assert(elf.ehdrField(.machine) == .LOONGARCH);
1299 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr));1489 link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr));
1300 },1490 },
1301 .rel64_hi12 => {1491 .larch_rel64_hi12 => {
1302 assert(elf.ehdrField(.machine) == .LOONGARCH);1492 assert(elf.ehdrField(.machine) == .LOONGARCH);
1303 link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr));1493 link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr));
1304 },1494 },
1305 // TODO: handle bad alignment and overflow gracefully1495 // TODO: handle bad alignment and overflow gracefully
1306 .branch_rel18 => {1496 .larch_branch_rel18 => {
1307 assert(elf.ehdrField(.machine) == .LOONGARCH);1497 assert(elf.ehdrField(.machine) == .LOONGARCH);
1308 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);1498 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
1309 const slot_target: i16 = @intCast(@shrExact(target_rel, 2));1499 const slot_target: i16 = @intCast(@shrExact(target_rel, 2));
1310 link.loongarch.writeK16(dest_slice[0..4], @bitCast(slot_target));1500 link.loongarch.writeK16(dest_slice[0..4], @bitCast(slot_target));
1311 },1501 },
1312 .branch_rel23 => {1502 .larch_branch_rel23 => {
1313 assert(elf.ehdrField(.machine) == .LOONGARCH);1503 assert(elf.ehdrField(.machine) == .LOONGARCH);
1314 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);1504 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
1315 const slot_target: i21 = @intCast(@shrExact(target_rel, 2));1505 const slot_target: i21 = @intCast(@shrExact(target_rel, 2));
1316 link.loongarch.writeD5K16(dest_slice[0..4], @bitCast(slot_target));1506 link.loongarch.writeD5K16(dest_slice[0..4], @bitCast(slot_target));
1317 },1507 },
1318 .branch_rel28 => {1508 .larch_branch_rel28 => {
1319 assert(elf.ehdrField(.machine) == .LOONGARCH);1509 assert(elf.ehdrField(.machine) == .LOONGARCH);
1320 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);1510 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
1321 const slot_target: i26 = @intCast(@shrExact(target_rel, 2));1511 const slot_target: i26 = @intCast(@shrExact(target_rel, 2));
1322 link.loongarch.writeD10K16(dest_slice[0..4], @bitCast(slot_target));1512 link.loongarch.writeD10K16(dest_slice[0..4], @bitCast(slot_target));
1323 },1513 },
1324 .call_rel38 => {1514 .larch_call_rel38 => {
1325 assert(elf.ehdrField(.machine) == .LOONGARCH);1515 assert(elf.ehdrField(.machine) == .LOONGARCH);
1326 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);1516 const target_rel: i64 = @bitCast(target_value -% dest_vaddr);
1327 // We use i64 instead of i36 here because the allowed range is1517 // We use i64 instead of i36 here because the allowed range is
...@@ -1331,22 +1521,109 @@ const SymbolReloc = struct {...@@ -1331,22 +1521,109 @@ const SymbolReloc = struct {
1331 link.loongarch.writeJ20(dest_slice[0..4], @bitCast(@as(i20, @intCast((slot_target +% 0x8000) >> 16))));1521 link.loongarch.writeJ20(dest_slice[0..4], @bitCast(@as(i20, @intCast((slot_target +% 0x8000) >> 16))));
1332 link.loongarch.writeK16(dest_slice[4..8], @bitCast(@as(i16, @truncate(slot_target))));1522 link.loongarch.writeK16(dest_slice[4..8], @bitCast(@as(i16, @truncate(slot_target))));
1333 },1523 },
1334 .tpoff32_lo12 => {1524 .larch_tpoff32_lo12 => {
1335 assert(elf.ehdrField(.machine) == .LOONGARCH);1525 assert(elf.ehdrField(.machine) == .LOONGARCH);
1336 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));1526 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value));
1337 },1527 },
1338 .tpoff32_hi20 => {1528 .larch_tpoff32_hi20 => {
1339 assert(elf.ehdrField(.machine) == .LOONGARCH);1529 assert(elf.ehdrField(.machine) == .LOONGARCH);
1340 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12));1530 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12));
1341 },1531 },
1342 .tpoff64_lo20 => {1532 .larch_tpoff64_lo20 => {
1343 assert(elf.ehdrField(.machine) == .LOONGARCH);1533 assert(elf.ehdrField(.machine) == .LOONGARCH);
1344 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32));1534 link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32));
1345 },1535 },
1346 .tpoff64_hi12 => {1536 .larch_tpoff64_hi12 => {
1347 assert(elf.ehdrField(.machine) == .LOONGARCH);1537 assert(elf.ehdrField(.machine) == .LOONGARCH);
1348 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52));1538 link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52));
1349 },1539 },
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 },
1350 }1627 }
1351 }1628 }
13521629
...@@ -1448,10 +1725,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {...@@ -1448,10 +1725,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
1448 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);1725 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14491726
1450 // Ensure the `.got.plt` section's node is big enough1727 // Ensure the `.got.plt` section's node is big enough
1451 const got_plt_need_size: usize = switch (elf.identClass()) {1728 const got_plt_need_size: usize = elf.targetPtrSize() * (3 + need_plt_capacity);
1452 .NONE, _ => unreachable,
1453 inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity),
1454 };
1455 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);1729 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
14561730
1457 // Ensure the `.plt.sec` section's node is big enough1731 // Ensure the `.plt.sec` section's node is big enough
...@@ -1460,16 +1734,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {...@@ -1460,16 +1734,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
1460 },1734 },
1461 .LOONGARCH => {1735 .LOONGARCH => {
1462 // Ensure the `.plt` section's node is big enough1736 // 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);
1464 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);1738 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14651739
1466 // Ensure the `.got.plt` section's node is big enough1740 // Ensure the `.got.plt` section's node is big enough
1467 const got_plt_need_size: usize = switch (elf.identClass()) {1741 const got_plt_need_size: usize = elf.targetPtrSize() * (2 + need_plt_capacity);
1468 .NONE, _ => unreachable,
1469 inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity),
1470 };
1471 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);1742 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
1472 },1743 },
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 },
1473 }1749 }
1474}1750}
1475/// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at1751/// 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...@@ -2090,23 +2366,17 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2090 .addend = 0,2366 .addend = 0,
2091 }));2367 }));
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)) {
2094 else => |machine| @panic(@tagName(machine)),2372 else => |machine| @panic(@tagName(machine)),
2095 .X86_64 => 3,2373 .LOONGARCH => .{ elf.shndx.got_plt, elf.targetPtrSize() * (2 + plt_index) },
2096 .LOONGARCH => 2,2374 .SPARCV9 => .{ elf.shndx.plt, 32 * (4 + plt_index) },
2375 .X86_64 => .{ elf.shndx.got_plt, elf.targetPtrSize() * (3 + plt_index) },
2097 };2376 };
20982377
2099 // Now that we know the index, we can set the relocation's offset.2378 // 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)) {2379 elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset);
2101 inline else => |shdr, class| got_plt_addr: {
2102 const ent_size = @sizeOf(class.ElfN().Addr);
2103 assert(elf.targetLoad(&shdr.entsize) == ent_size);
2104 const offset = ent_size * @as(u64, reserved_got_plt_entries + plt_index);
2105 assert(offset <= elf.targetLoad(&shdr.size));
2106 break :got_plt_addr elf.targetLoad(&shdr.addr) + offset;
2107 },
2108 };
2109 elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_addr);
21102380
2111 if (plt_index < elf.plt.count()) {2381 if (plt_index < elf.plt.count()) {
2112 // We reused a free entry, so we're already done!2382 // 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...@@ -2148,13 +2418,11 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2148 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;2418 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
2149 switch (elf.shdrPtr(elf.shndx.got_plt)) {2419 switch (elf.shdrPtr(elf.shndx.got_plt)) {
2150 inline else => |shdr, class| {2420 inline else => |shdr, class| {
2151 const ent_size = @sizeOf(class.ElfN().Addr);2421 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2152 const old_size = ent_size * (3 + plt_index);2422 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(class.ElfN().Addr));
2153 assert(elf.targetLoad(&shdr.size) == old_size);
2154 elf.targetStore(&shdr.size, old_size + ent_size);
2155 std.mem.writeInt(2423 std.mem.writeInt(
2156 class.ElfN().Addr,2424 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)],
2158 @intCast(plt_addr),2426 @intCast(plt_addr),
2159 target_endian,2427 target_endian,
2160 );2428 );
...@@ -2176,7 +2444,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2176,7 +2444,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2176 i32,2444 i32,
2177 plt_sec_slice[6..][0..4],2445 plt_sec_slice[6..][0..4],
2178 @intCast(@as(i64, @bitCast(2446 @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),
2180 ))),2448 ))),
2181 target_endian,2449 target_endian,
2182 );2450 );
...@@ -2212,26 +2480,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2212,26 +2480,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2212 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;2480 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
2213 switch (elf.shdrPtr(elf.shndx.got_plt)) {2481 switch (elf.shdrPtr(elf.shndx.got_plt)) {
2214 inline else => |shdr, class| {2482 inline else => |shdr, class| {
2215 const ent_size = @sizeOf(class.ElfN().Addr);2483 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2216 const old_size = ent_size * (2 + plt_index);2484 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(class.ElfN().Addr));
2217 assert(elf.targetLoad(&shdr.size) == old_size);
2218 elf.targetStore(&shdr.size, old_size + ent_size);
2219 std.mem.writeInt(2485 std.mem.writeInt(
2220 class.ElfN().Addr,2486 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)],
2222 @intCast(plt_addr),2488 @intCast(plt_addr),
2223 target_endian,2489 target_endian,
2224 );2490 );
2225 assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size));
2226 },2491 },
2227 }2492 }
22282493
2229 // relocate the PLT entry to point to the .GOT.PLT entry2494 // 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;
2231 // TODO: handle overflow gracefully2496 // TODO: handle overflow gracefully
2232 link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr));2497 link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr));
2233 link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs));2498 link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs));
2234 },2499 },
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 },
2235 }2531 }
2236}2532}
22372533
...@@ -2622,12 +2918,12 @@ pub const ExternSymbolOpts = struct {...@@ -2622,12 +2918,12 @@ pub const ExternSymbolOpts = struct {
2622};2918};
2623pub fn externSymbol(elf: *Elf, opts: ExternSymbolOpts) link.Error!link.File.SymbolId {2919pub fn externSymbol(elf: *Elf, opts: ExternSymbolOpts) link.Error!link.File.SymbolId {
2624 const diags = &elf.base.comp.link_diags;2920 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) {
2626 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),2922 error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}),
2627 else => |e| return e,2923 else => |e| return e,
2628 };2924 }).toTypeErased();
2629}2925}
2630fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!link.File.SymbolId {2926fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!Symbol.Id {
2631 try elf.ensureUnusedSymbolCapacity(1, .maybe_global);2927 try elf.ensureUnusedSymbolCapacity(1, .maybe_global);
2632 const symbol = elf.addGlobalSymbolAssumeCapacity(.{2928 const symbol = elf.addGlobalSymbolAssumeCapacity(.{
2633 .node = .none,2929 .node = .none,
...@@ -2651,7 +2947,7 @@ fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!link.File.SymbolId...@@ -2651,7 +2947,7 @@ fn externSymbolInner(elf: *Elf, opts: ExternSymbolOpts) Error!link.File.SymbolId
2651 }) catch |err| switch (err) {2947 }) catch |err| switch (err) {
2652 error.MultipleDefinitions => unreachable, // shndx is undef2948 error.MultipleDefinitions => unreachable, // shndx is undef
2653 };2949 };
2654 return symbol.toTypeErased();2950 return symbol;
2655}2951}
2656pub fn addReloc(2952pub fn addReloc(
2657 elf: *Elf,2953 elf: *Elf,
...@@ -3084,11 +3380,12 @@ fn initHeaders(...@@ -3084,11 +3380,12 @@ fn initHeaders(
3084 .@"64" => .@"8",3380 .@"64" => .@"8",
3085 };3381 };
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 =
3088 switch (machine) {3384 switch (machine) {
3089 else => @panic(@tagName(machine)),3385 else => @panic(@tagName(machine)),
3090 .X86_64 => .{ 16, .@"16", true },3386 .LOONGARCH => .{ 16 * 2, .@"4", true, false },
3091 .LOONGARCH => .{ 32, .@"4", false },3387 .SPARCV9 => .{ 32 * 4, .fromByteUnits(256), false, false },
3388 .X86_64 => .{ 16, .@"16", true, true },
3092 };3389 };
30933390
3094 const shnum: u32 = shnum: {3391 const shnum: u32 = shnum: {
...@@ -3111,7 +3408,7 @@ fn initHeaders(...@@ -3111,7 +3408,7 @@ fn initHeaders(
3111 }3408 }
3112 if (@"type" != .REL) {3409 if (@"type" != .REL) {
3113 shnum += 1; // .got3410 shnum += 1; // .got
3114 shnum += 1; // .got.plt3411 shnum += @intFromBool(got_plt); // .got.plt
3115 shnum += 1; // .plt3412 shnum += 1; // .plt
3116 shnum += @intFromBool(plt_sec); // .plt_sec3413 shnum += @intFromBool(plt_sec); // .plt_sec
3117 }3414 }
...@@ -3212,7 +3509,6 @@ fn initHeaders(...@@ -3212,7 +3509,6 @@ fn initHeaders(
3212 ehdr.phoff = 0;3509 ehdr.phoff = 0;
3213 ehdr.shoff = 0;3510 ehdr.shoff = 0;
3214 ehdr.flags = switch (machine) {3511 ehdr.flags = switch (machine) {
3215 .X86_64 => 0,
3216 .LOONGARCH => e_flags: {3512 .LOONGARCH => e_flags: {
3217 const target_cpu = &elf.base.comp.getTarget().cpu;3513 const target_cpu = &elf.base.comp.getTarget().cpu;
3218 const e_flags: std.elf.loongarch.EFlags = .{3514 const e_flags: std.elf.loongarch.EFlags = .{
...@@ -3227,6 +3523,20 @@ fn initHeaders(...@@ -3227,6 +3523,20 @@ fn initHeaders(
3227 };3523 };
3228 break :e_flags @bitCast(e_flags);3524 break :e_flags @bitCast(e_flags);
3229 },3525 },
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,
3230 else => @panic(@tagName(machine)),3540 else => @panic(@tagName(machine)),
3231 };3541 };
3232 ehdr.ehsize = @sizeOf(ElfN.Ehdr);3542 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
...@@ -3247,6 +3557,31 @@ fn initHeaders(...@@ -3247,6 +3557,31 @@ fn initHeaders(
3247 }));3557 }));
3248 elf.nodes.appendAssumeCapacity(.shdr);3558 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
3250 var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: {3585 var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: {
3251 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{3586 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
3252 .alignment = elf.mf.flags.block_size,3587 .alignment = elf.mf.flags.block_size,
...@@ -3299,8 +3634,8 @@ fn initHeaders(...@@ -3299,8 +3634,8 @@ fn initHeaders(
3299 .@"386" => 0x400000,3634 .@"386" => 0x400000,
3300 .AARCH64, .X86_64 => 0x200000,3635 .AARCH64, .X86_64 => 0x200000,
3301 .PPC, .PPC64 => 0x10000000,3636 .PPC, .PPC64 => 0x10000000,
3302 .S390, .S390_OLD => 0x1000000,3637 .S390 => 0x1000000,
3303 .OLD_SPARCV9, .SPARCV9 => 0x100000,3638 .SPARCV9 => 0x100000,
3304 else => 0x10000,3639 else => 0x10000,
3305 },3640 },
3306 };3641 };
...@@ -3351,7 +3686,7 @@ fn initHeaders(...@@ -3351,7 +3686,7 @@ fn initHeaders(
3351 .filesz = @intCast(rodata_size),3686 .filesz = @intCast(rodata_size),
3352 .memsz = @intCast(rodata_size),3687 .memsz = @intCast(rodata_size),
3353 .flags = .{ .R = true },3688 .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()),
3355 };3690 };
3356 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);3691 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
3357 ph_vaddr += @intCast(rodata_size);3692 ph_vaddr += @intCast(rodata_size);
...@@ -3366,7 +3701,7 @@ fn initHeaders(...@@ -3366,7 +3701,7 @@ fn initHeaders(
3366 .filesz = @intCast(text_size),3701 .filesz = @intCast(text_size),
3367 .memsz = @intCast(text_size),3702 .memsz = @intCast(text_size),
3368 .flags = .{ .R = true, .X = true },3703 .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()),
3370 };3705 };
3371 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);3706 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
3372 ph_vaddr += @intCast(text_size);3707 ph_vaddr += @intCast(text_size);
...@@ -3381,7 +3716,7 @@ fn initHeaders(...@@ -3381,7 +3716,7 @@ fn initHeaders(
3381 .filesz = @intCast(data_size),3716 .filesz = @intCast(data_size),
3382 .memsz = @intCast(data_size),3717 .memsz = @intCast(data_size),
3383 .flags = .{ .R = true, .W = true },3718 .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()),
3385 };3720 };
3386 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);3721 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
3387 ph_vaddr += @intCast(data_size);3722 ph_vaddr += @intCast(data_size);
...@@ -3536,14 +3871,16 @@ fn initHeaders(...@@ -3536,14 +3871,16 @@ fn initHeaders(
3536 // Reserve space for the reserved words, populated later.3871 // Reserve space for the reserved words, populated later.
3537 .size = switch (machine) {3872 .size = switch (machine) {
3538 else => @panic(@tagName(machine)),3873 else => @panic(@tagName(machine)),
3539 .X86_64 => 3 * 8,3874 .X86_64 => 3 * elf.targetPtrSize(),
3540 .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4,3875 .LOONGARCH,
3876 .SPARCV9,
3877 => elf.targetPtrSize(),
3541 },3878 },
3542 .flags = .{ .WRITE = true, .ALLOC = true },3879 .flags = .{ .WRITE = true, .ALLOC = true },
3543 .addralign = addr_align,3880 .addralign = addr_align,
3544 .entsize = @intCast(addr_align.toByteUnits()),3881 .entsize = @intCast(addr_align.toByteUnits()),
3545 });3882 });
3546 elf.shndx.got_plt = try elf.addSection(3883 if (got_plt) elf.shndx.got_plt = try elf.addSection(
3547 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,3884 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
3548 .{3885 .{
3549 .name = ".got.plt",3886 .name = ".got.plt",
...@@ -3553,7 +3890,7 @@ fn initHeaders(...@@ -3553,7 +3890,7 @@ fn initHeaders(
3553 else => @panic(@tagName(machine)),3890 else => @panic(@tagName(machine)),
3554 .@"386" => 3 * 4,3891 .@"386" => 3 * 4,
3555 .X86_64 => 3 * 8,3892 .X86_64 => 3 * 8,
3556 .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4,3893 .LOONGARCH => 2 * elf.targetPtrSize(),
3557 },3894 },
3558 .addralign = addr_align,3895 .addralign = addr_align,
3559 .entsize = @intCast(addr_align.toByteUnits()),3896 .entsize = @intCast(addr_align.toByteUnits()),
...@@ -3562,7 +3899,14 @@ fn initHeaders(...@@ -3562,7 +3899,14 @@ fn initHeaders(
3562 elf.shndx.plt = try elf.addSection(elf.ni.text, .{3899 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
3563 .name = ".plt",3900 .name = ".plt",
3564 .type = .PROGBITS,3901 .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 },
3566 .size = init_plt_size,3910 .size = init_plt_size,
3567 .addralign = plt_align,3911 .addralign = plt_align,
3568 .node_align = elf.mf.flags.block_size,3912 .node_align = elf.mf.flags.block_size,
...@@ -3661,7 +4005,7 @@ fn initHeaders(...@@ -3661,7 +4005,7 @@ fn initHeaders(
3661 .type = .RELA,4005 .type = .RELA,
3662 .flags = .{ .ALLOC = true, .INFO_LINK = true },4006 .flags = .{ .ALLOC = true, .INFO_LINK = true },
3663 .link = elf.shndx.dynsym.toSection().?,4007 .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().?,
3665 .addralign = addr_align,4009 .addralign = addr_align,
3666 .entsize = rela_size,4010 .entsize = rela_size,
3667 .node_align = elf.mf.flags.block_size,4011 .node_align = elf.mf.flags.block_size,
...@@ -3729,10 +4073,11 @@ fn initHeaders(...@@ -3729,10 +4073,11 @@ fn initHeaders(
3729 });4073 });
3730 elf.plt_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len);4074 elf.plt_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len);
3731 try elf.ensureUnusedRelocCapacity(plt_ni, 3);4075 try elf.ensureUnusedRelocCapacity(plt_ni, 3);
3732 try elf.addSymbolRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .rel32_hi20);4076 try elf.addSymbolRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .larch_rel32_hi20);
3733 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12);4077 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .larch_abs32_lo12);
3734 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12);4078 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .larch_abs32_lo12);
3735 },4079 },
4080 .SPARCV9 => {},
3736 }4081 }
3737 }4082 }
3738 if (comp.config.any_non_single_threaded) {4083 if (comp.config.any_non_single_threaded) {
...@@ -3757,7 +4102,9 @@ fn initHeaders(...@@ -3757,7 +4102,9 @@ fn initHeaders(
3757 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none);4102 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none);
3758 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none);4103 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none);
3759 },4104 },
3760 .LOONGARCH => {4105 .LOONGARCH,
4106 .SPARCV9,
4107 => {
3761 try elf.got.ensureUnusedCapacity(gpa, 1);4108 try elf.got.ensureUnusedCapacity(gpa, 1);
3762 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {4109 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {
3763 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },4110 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
...@@ -4075,35 +4422,38 @@ fn identData(elf: *const Elf) std.elf.DATA {...@@ -4075,35 +4422,38 @@ fn identData(elf: *const Elf) std.elf.DATA {
4075 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);4422 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
4076}4423}
40774424
4425fn targetPtrSize(elf: *const Elf) u32 {
4426 return elf.identClass().size();
4427}
4078fn targetEndian(elf: *const Elf) std.lang.Endian {4428fn targetEndian(elf: *const Elf) std.lang.Endian {
4079 return switch (elf.identData()) {4429 return elf.identData().endian();
4080 .NONE, _ => unreachable,
4081 .@"2LSB" => .little,
4082 .@"2MSB" => .big,
4083 };
4084}4430}
4085fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child {4431fn 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);
4087 return switch (@typeInfo(Child)) {4435 return switch (@typeInfo(Child)) {
4088 else => @compileError(@typeName(Child)),4436 else => @compileError(@typeName(Child)),
4089 .int => std.mem.toNative(Child, ptr.*, elf.targetEndian()),4437 .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)))),
4091 .@"struct" => |@"struct"| @bitCast(4439 .@"struct" => |@"struct"| @bitCast(
4092 elf.targetLoad(@as(*@"struct".backing_integer.?, @ptrCast(ptr))),4440 elf.targetLoad(@as(*align(alignment) @"struct".backing_integer.?, @ptrCast(ptr))),
4093 ),4441 ),
4094 };4442 };
4095}4443}
4096fn targetStore(elf: *const Elf, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).pointer.child) void {4444fn 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);
4098 return switch (@typeInfo(Child)) {4448 return switch (@typeInfo(Child)) {
4099 else => @compileError(@typeName(Child)),4449 else => @compileError(@typeName(Child)),
4100 .int => ptr.* = std.mem.nativeTo(Child, val, elf.targetEndian()),4450 .int => ptr.* = std.mem.nativeTo(Child, val, elf.targetEndian()),
4101 .@"enum" => |@"enum"| elf.targetStore(4451 .@"enum" => |@"enum"| elf.targetStore(
4102 @as(*@"enum".tag_type, @ptrCast(ptr)),4452 @as(*align(alignment) @"enum".tag_type, @ptrCast(ptr)),
4103 @intFromEnum(val),4453 @intFromEnum(val),
4104 ),4454 ),
4105 .@"struct" => |@"struct"| elf.targetStore(4455 .@"struct" => |@"struct"| elf.targetStore(
4106 @as(*@"struct".backing_integer.?, @ptrCast(ptr)),4456 @as(*align(alignment) @"struct".backing_integer.?, @ptrCast(ptr)),
4107 @bitCast(val),4457 @bitCast(val),
4108 ),4458 ),
4109 };4459 };
...@@ -5433,6 +5783,11 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -5433,6 +5783,11 @@ fn prelinkInner(elf: *Elf) Error!void {
5433 };5783 };
5434 }5784 }
54355785
5786 const got_plt = switch (elf.ehdrField(.machine)) {
5787 .SPARCV9 => false,
5788 else => true,
5789 };
5790
5436 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {5791 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
5437 .NONE, _ => unreachable,5792 .NONE, _ => unreachable,
5438 inline else => |ct_class| {5793 inline else => |ct_class| {
...@@ -5616,7 +5971,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -5616,7 +5971,7 @@ fn prelinkInner(elf: *Elf) Error!void {
5616 if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity(5971 if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity(
5617 dynamic_ni,5972 dynamic_ni,
5618 @sizeOf(ElfN.Addr) * (2 * index + 1),5973 @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),
5620 0,5975 0,
5621 dsorel,5976 dsorel,
5622 );5977 );
...@@ -5938,33 +6293,141 @@ fn addRelocAssumeCapacity(...@@ -5938,33 +6293,141 @@ fn addRelocAssumeCapacity(
5938 .@"64_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64),6293 .@"64_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64),
5939 .@"32_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32),6294 .@"32_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32),
59406295
5941 .PCALA_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32_lo12),6296 .PCALA_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_abs32_lo12),
5942 .PCALA_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32_hi20),6297 .PCALA_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_rel32_hi20),
5943 .PCALA64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_hi12),6298 .PCALA64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_rel64_hi12),
5944 .PCALA64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_lo20),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),6301 .B16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_branch_rel18),
5947 .B21 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel23),6302 .B21 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_branch_rel23),
5948 .B26 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel28),6303 .B26 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_branch_rel28),
5949 .CALL36 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .call_rel38),6304 .CALL36 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_call_rel38),
59506305
5951 // Relocations targeting a TLS symbol6306 // Relocations targeting a TLS symbol
5952 .TLS_LE_LO12, .TLS_LE_LO12_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_lo12),6307 .TLS_LE_LO12, .TLS_LE_LO12_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff32_lo12),
5953 .TLS_LE_HI20, .TLS_LE_HI20_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_hi20),6308 .TLS_LE_HI20, .TLS_LE_HI20_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff32_hi20),
5954 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_lo20),6309 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff64_lo20),
5955 .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_hi12),6310 .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .larch_tpoff64_hi12),
5956 .TLS_LE_ADD_R => {}, // TODO: relaxation is not yet implemented6311 .TLS_LE_ADD_R => {}, // TODO: relaxation is not yet implemented
59576312
5958 // Relocations targeting a GOT entry6313 // Relocations targeting a GOT entry
5959 .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12),6314 .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs32_lo12),
5960 .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel32_hi20),6315 .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_rel32_hi20),
5961 .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_lo20),6316 .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_rel64_lo20),
5962 .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_hi12),6317 .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_rel64_hi12),
59636318
5964 .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12),6319 .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs32_lo12),
5965 .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_hi20),6320 .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs32_hi20),
5966 .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_lo20),6321 .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .larch_abs64_lo20),
5967 .GOT64_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_hi12),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 => {},
5968 },6431 },
5969 },6432 },
5970 }6433 }
...@@ -6008,29 +6471,46 @@ fn addSymbolRelocAssumeCapacity(...@@ -6008,29 +6471,46 @@ fn addSymbolRelocAssumeCapacity(
6008 },6471 },
6009 .abs64 => .@"64",6472 .abs64 => .@"64",
6010 .abs32 => .@"32",6473 .abs32 => .@"32",
6474 .abs16 => unreachable,
6475 .abs8 => unreachable,
6011 .abs32s => .@"32S",6476 .abs32s => .@"32S",
6012 .rel64 => .PC64,6477 .rel64 => .PC64,
6013 .rel32 => .PC32,6478 .rel32 => .PC32,
6014 .pltrel64 => break :r .none,6479 .rel16 => unreachable,
6015 .pltrel32 => break :r .none,6480 .rel8 => unreachable,
6481 .pltabs64, .pltabs32, .pltrel64, .pltrel32 => break :r .none,
6016 .dtpoff64 => .DTPOFF64,6482 .dtpoff64 => .DTPOFF64,
6017 .dtpoff32 => .DTPOFF32,6483 .dtpoff32 => .DTPOFF32,
6018 .tpoff64 => .TPOFF64,6484 .tpoff64 => .TPOFF64,
6019 .tpoff32 => .TPOFF32,6485 .tpoff32 => .TPOFF32,
6020 .size64 => .SIZE64,6486 .size64 => .SIZE64,
6021 .size32 => .SIZE32,6487 .size32 => .SIZE32,
6022 .abs32_lo12,6488
6023 .rel32_hi20,6489 .larch_abs32_lo12,
6024 .rel64_lo20,6490 .larch_rel32_hi20,
6025 .rel64_hi12,6491 .larch_rel64_lo20,
6026 .branch_rel18,6492 .larch_rel64_hi12,
6027 .branch_rel23,6493 .larch_branch_rel18,
6028 .branch_rel28,6494 .larch_branch_rel23,
6029 .call_rel38,6495 .larch_branch_rel28,
6030 .tpoff32_lo12,6496 .larch_call_rel38,
6031 .tpoff32_hi20,6497 .larch_tpoff32_lo12,
6032 .tpoff64_lo20,6498 .larch_tpoff32_hi20,
6033 .tpoff64_hi12,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,
6034 => unreachable,6514 => unreachable,
6035 } },6515 } },
6036 .LOONGARCH => .{ .LOONGARCH = switch (@"type") {6516 .LOONGARCH => .{ .LOONGARCH = switch (@"type") {
...@@ -6041,26 +6521,95 @@ fn addSymbolRelocAssumeCapacity(...@@ -6041,26 +6521,95 @@ fn addSymbolRelocAssumeCapacity(
6041 },6521 },
6042 .abs64 => .@"64",6522 .abs64 => .@"64",
6043 .abs32 => .@"32",6523 .abs32 => .@"32",
6044 .abs32s, .size64, .size32 => unreachable,6524 .abs32s => unreachable,
6525 .abs16 => unreachable,
6526 .abs8 => unreachable,
6045 .rel64 => .@"64_PCREL",6527 .rel64 => .@"64_PCREL",
6046 .rel32 => .@"32_PCREL",6528 .rel32 => .@"32_PCREL",
6047 .pltrel64, .pltrel32 => break :r .none,6529 .rel16 => unreachable,
6530 .rel8 => unreachable,
6531 .pltabs64, .pltabs32, .pltrel64, .pltrel32 => break :r .none,
6048 .dtpoff64 => .TLS_DTPREL64,6532 .dtpoff64 => .TLS_DTPREL64,
6049 .dtpoff32 => .TLS_DTPREL32,6533 .dtpoff32 => .TLS_DTPREL32,
6050 .tpoff64 => .TLS_TPREL64,6534 .tpoff64 => .TLS_TPREL64,
6051 .tpoff32 => .TLS_TPREL32,6535 .tpoff32 => .TLS_TPREL32,
6052 .abs32_lo12 => .PCALA_LO12,6536 .size64 => unreachable,
6053 .rel32_hi20 => .PCALA_HI20,6537 .size32 => unreachable,
6054 .rel64_lo20 => .PCALA64_LO20,6538
6055 .rel64_hi12 => .PCALA64_HI12,6539 .larch_abs32_lo12 => .PCALA_LO12,
6056 .branch_rel18 => .B16,6540 .larch_rel32_hi20 => .PCALA_HI20,
6057 .branch_rel23 => .B21,6541 .larch_rel64_lo20 => .PCALA64_LO20,
6058 .branch_rel28 => .B26,6542 .larch_rel64_hi12 => .PCALA64_HI12,
6059 .call_rel38 => .CALL36,6543 .larch_branch_rel18 => .B16,
6060 .tpoff32_lo12 => .TLS_LE_LO12,6544 .larch_branch_rel23 => .B21,
6061 .tpoff32_hi20 => .TLS_LE_HI20,6545 .larch_branch_rel28 => .B26,
6062 .tpoff64_lo20 => .TLS_LE64_LO20,6546 .larch_call_rel38 => .CALL36,
6063 .tpoff64_hi12 => .TLS_LE64_HI12,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,
6064 } },6613 } },
6065 };6614 };
60666615
...@@ -6221,8 +6770,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -6221,8 +6770,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
6221 }6770 }
6222 const reloc_type: MachineRelocType = switch (elf.ehdrField(.machine)) {6771 const reloc_type: MachineRelocType = switch (elf.ehdrField(.machine)) {
6223 else => |machine| @panic(@tagName(machine)),6772 else => |machine| @panic(@tagName(machine)),
6224 .X86_64 => .{ .X86_64 = .TPOFF64 },
6225 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },6773 .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 },
6226 };6776 };
6227 break :val switch (sym_id.unwrap()) {6777 break :val switch (sym_id.unwrap()) {
6228 // For global symbols, just target the right dynsym with no addend.6778 // For global symbols, just target the right dynsym with no addend.
...@@ -6270,8 +6820,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -6270,8 +6820,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
6270 .dynamic => .{ .reloc = .{6820 .dynamic => .{ .reloc = .{
6271 .type = switch (elf.ehdrField(.machine)) {6821 .type = switch (elf.ehdrField(.machine)) {
6272 else => |machine| @panic(@tagName(machine)),6822 else => |machine| @panic(@tagName(machine)),
6273 .X86_64 => .{ .X86_64 = .DTPMOD64 },
6274 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },6823 .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 },
6275 },6826 },
6276 .dynsym_index = switch (elf.classifySymbolValue(sym)) {6827 .dynsym_index = switch (elf.classifySymbolValue(sym)) {
6277 .static, .static_relative => 0,6828 .static, .static_relative => 0,
...@@ -6288,8 +6839,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -6288,8 +6839,9 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
6288 .dynamic => .{ .reloc = .{6839 .dynamic => .{ .reloc = .{
6289 .type = switch (elf.ehdrField(.machine)) {6840 .type = switch (elf.ehdrField(.machine)) {
6290 else => |machine| @panic(@tagName(machine)),6841 else => |machine| @panic(@tagName(machine)),
6291 .X86_64 => .{ .X86_64 = .DTPMOD64 },
6292 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },6842 .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 },
6293 },6845 },
6294 .dynsym_index = 0,6846 .dynsym_index = 0,
6295 .addend = 0,6847 .addend = 0,
...@@ -7341,6 +7893,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad...@@ -7341,6 +7893,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
7341 },7893 },
7342 }7894 }
7343 },7895 },
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 },
7344 }7907 }
7345}7908}
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};