reloc_apply_test.c (12233B)
1 /* Relocation byte-encoder migration guard (doc/plan/RELOC.md, WS-C). 2 * 3 * WS-C moves the per-arch *instruction-immediate* byte encoders out of the 4 * format-neutral src/obj/reloc_apply.c into each backend's 5 * src/arch/<arch>/reloc.c (reached via LinkArchDesc.reloc_apply_insn), while 6 * link_reloc_apply stays the single public byte-patcher entry. The move must 7 * be byte-identical: the dispatcher routes each kind to the same encoder it 8 * had before, producing the same patched bytes. 9 * 10 * This test pins that. For one representative, in-range relocation of every 11 * instruction-embedded kind (plus a sampling of the arch-neutral data-word 12 * kinds the obj core keeps), it drives link_reloc_apply and asserts the 13 * patched bytes equal a frozen golden. The goldens were captured from the 14 * pre-WS-C implementation; do not "improve" them — they are the spec the 15 * partitioned encoders must match. A drift in any encoder turns this red and 16 * bisects to the exact kind (hence arch). 17 * 18 * Run with KIT_RELOC_APPLY_CAPTURE=1 in the environment to re-emit the golden 19 * column (used once to seed it from the frozen implementation). 20 * 21 * Exit 0 = pass; non-zero = fail. */ 22 23 #include "obj/reloc_apply.h" 24 25 #include <kit/cg.h> 26 #include <kit/core.h> 27 28 #include "core/core.h" 29 #include "lib/kit_unit.h" 30 #include "obj/obj.h" 31 32 static KitUnit g_u; 33 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 34 35 typedef struct ApplyCase { 36 const char* name; 37 KitArchKind arch; 38 RelocKind kind; 39 u64 in; /* initial site bytes, little-endian packed */ 40 u32 nbytes; /* bytes the encoder touches / we compare */ 41 u64 S; 42 i64 A; 43 u64 P; 44 u64 want; /* golden patched bytes, little-endian packed */ 45 } ApplyCase; 46 47 /* Instruction-immediate encoders (the WS-C movers) plus a sampling of the 48 * arch-neutral data-word arms the obj core retains. Inputs are chosen 49 * in-range so no encoder range check panics. */ 50 static const ApplyCase kCases[] = { 51 /* ---- AArch64 instruction-immediate encoders ---- */ 52 {"aa64 CONDBR19", KIT_ARCH_ARM_64, R_AARCH64_CONDBR19, 0x54000000u, 4, 53 0x2000, 0, 0x1000, 0x54008000u}, 54 {"aa64 LD_PREL_LO19", KIT_ARCH_ARM_64, R_AARCH64_LD_PREL_LO19, 0x58000000u, 55 4, 0x2000, 0, 0x1000, 0x58008000u}, 56 {"aa64 TSTBR14", KIT_ARCH_ARM_64, R_AARCH64_TSTBR14, 0x36000000u, 4, 0x1100, 57 0, 0x1000, 0x36000800u}, 58 {"aa64 ADR_PREL_LO21", KIT_ARCH_ARM_64, R_AARCH64_ADR_PREL_LO21, 59 0x10000000u, 4, 0x1234, 0, 0x1000, 0x100011a0u}, 60 {"aa64 JUMP26", KIT_ARCH_ARM_64, R_AARCH64_JUMP26, 0x14000000u, 4, 0x5000, 61 0, 0x1000, 0x14001000u}, 62 {"aa64 CALL26", KIT_ARCH_ARM_64, R_AARCH64_CALL26, 0x94000000u, 4, 0x5000, 63 0, 0x1000, 0x94001000u}, 64 {"aa64 ADR_PREL_PG_HI21", KIT_ARCH_ARM_64, R_AARCH64_ADR_PREL_PG_HI21, 65 0x90000000u, 4, 0x100000, 0, 0x1000, 0xf00007e0u}, 66 {"aa64 ADR_PREL_PG_HI21_NC", KIT_ARCH_ARM_64, R_AARCH64_ADR_PREL_PG_HI21_NC, 67 0x90000000u, 4, 0x100000, 0, 0x1000, 0xf00007e0u}, 68 {"aa64 ADR_GOT_PAGE", KIT_ARCH_ARM_64, R_AARCH64_ADR_GOT_PAGE, 0x90000000u, 69 4, 0x100000, 0, 0x1000, 0xf00007e0u}, 70 {"aa64 POINTER_TO_GOT", KIT_ARCH_ARM_64, R_AARCH64_POINTER_TO_GOT, 0, 4, 71 0x2000, 4, 0x1000, 0x1004u}, 72 {"aa64 TLSDESC_ADR_PAGE21", KIT_ARCH_ARM_64, R_AARCH64_TLSDESC_ADR_PAGE21, 73 0x90000000u, 4, 0x123456789abcdef0ull, 0, 0, 0xd29bde00u}, 74 {"aa64 TLSDESC_LD64_LO12", KIT_ARCH_ARM_64, R_AARCH64_TLSDESC_LD64_LO12, 75 0xf9400004u, 4, 0x123456789abcdef0ull, 0, 0, 0xf2b35780u}, 76 {"aa64 TLSDESC_ADD_LO12", KIT_ARCH_ARM_64, R_AARCH64_TLSDESC_ADD_LO12, 77 0x91000000u, 4, 0x123456789abcdef0ull, 0, 0, 0xf2cacf00u}, 78 {"aa64 TLSDESC_CALL", KIT_ARCH_ARM_64, R_AARCH64_TLSDESC_CALL, 0xd63f0080u, 79 4, 0x123456789abcdef0ull, 0, 0, 0xf2e24680u}, 80 {"aa64 TLSIE_ADR_GOTTPREL_PAGE21", KIT_ARCH_ARM_64, 81 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, 0x90000000u, 4, 0x100000, 0, 0x1000, 82 0xf00007e0u}, 83 {"aa64 TLVP_LOAD_PAGE21", KIT_ARCH_ARM_64, R_AARCH64_TLVP_LOAD_PAGE21, 84 0x90000000u, 4, 0x100000, 0, 0x1000, 0xf00007e0u}, 85 {"aa64 ADD_ABS_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_ADD_ABS_LO12_NC, 86 0x91000000u, 4, 0x1abc, 0, 0, 0x912af000u}, 87 {"aa64 TLSLE_ADD_TPREL_HI12", KIT_ARCH_ARM_64, 88 R_AARCH64_TLSLE_ADD_TPREL_HI12, 0x91000000u, 4, 0x12345, 0, 0, 89 0x91004800u}, 90 {"aa64 TLSLE_ADD_TPREL_LO12_NC", KIT_ARCH_ARM_64, 91 R_AARCH64_TLSLE_ADD_TPREL_LO12_NC, 0x91000000u, 4, 0x12345, 0, 0, 92 0x910d1400u}, 93 {"aa64 LDST8_ABS_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_LDST8_ABS_LO12_NC, 94 0xf9400000u, 4, 0x1100, 0, 0, 0xf9440000u}, 95 {"aa64 LDST16_ABS_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_LDST16_ABS_LO12_NC, 96 0xf9400000u, 4, 0x1100, 0, 0, 0xf9420000u}, 97 {"aa64 LDST32_ABS_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_LDST32_ABS_LO12_NC, 98 0xf9400000u, 4, 0x1100, 0, 0, 0xf9410000u}, 99 {"aa64 LDST64_ABS_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_LDST64_ABS_LO12_NC, 100 0xf9400000u, 4, 0x1100, 0, 0, 0xf9408000u}, 101 {"aa64 LDST128_ABS_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_LDST128_ABS_LO12_NC, 102 0xf9400000u, 4, 0x1100, 0, 0, 0xf9404000u}, 103 {"aa64 LD64_GOT_LO12_NC", KIT_ARCH_ARM_64, R_AARCH64_LD64_GOT_LO12_NC, 104 0xf9400000u, 4, 0x1100, 0, 0, 0xf9408000u}, 105 {"aa64 TLSIE_LD64_GOTTPREL_LO12_NC", KIT_ARCH_ARM_64, 106 R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, 0xf9400000u, 4, 0x1100, 0, 0, 107 0xf9408000u}, 108 {"aa64 TLVP_LOAD_PAGEOFF12", KIT_ARCH_ARM_64, R_AARCH64_TLVP_LOAD_PAGEOFF12, 109 0xf9400000u, 4, 0x1100, 0, 0, 0xf9408000u}, 110 /* ---- AArch64 neutral data words (kept in obj core) ---- */ 111 {"aa64 ABS16", KIT_ARCH_ARM_64, R_ABS16, 0x0000u, 2, 0x1234, 0, 0, 0x1234u}, 112 {"aa64 PREL16", KIT_ARCH_ARM_64, R_PREL16, 0x0000u, 2, 0x2000, 0, 0x1000, 113 0x1000u}, 114 115 /* ---- x86-64 instruction-immediate + neutral data words ---- */ 116 {"x64 PC8", KIT_ARCH_X86_64, R_X64_PC8, 0x00u, 1, 0x1010, -2, 0x1000, 117 0x0eu}, 118 {"x64 ABS32", KIT_ARCH_X86_64, R_ABS32, 0x0u, 4, 0xdeadbeefu, 0, 0, 119 0xdeadbeefu}, 120 {"x64 ABS64", KIT_ARCH_X86_64, R_ABS64, 0x0u, 8, 0x1122334455667788ull, 0, 121 0, 0x1122334455667788ull}, 122 {"x64 PC32", KIT_ARCH_X86_64, R_PC32, 0x0u, 4, 0x2000, -4, 0x1000, 0xffcu}, 123 {"x64 TPOFF32", KIT_ARCH_X86_64, R_X64_TPOFF32, 0x0u, 4, 0x12345678u, 0, 0, 124 0x12345678u}, 125 {"x64 DTPOFF32", KIT_ARCH_X86_64, R_X64_DTPOFF32, 0x0u, 4, 0x87654321u, 0, 126 0, 0x87654321u}, 127 {"x64 GLOB_DAT", KIT_ARCH_X86_64, R_X64_GLOB_DAT, 0x0u, 8, 0xcafebabeu, 0, 128 0, 0xcafebabeu}, 129 130 /* ---- RISC-V instruction-immediate encoders ---- */ 131 {"rv HI20", KIT_ARCH_RV64, R_RV_HI20, 0x00000537u, 4, 0x12345, 0, 0, 132 0x00012537u}, 133 {"rv TPREL_HI20", KIT_ARCH_RV64, R_RV_TPREL_HI20, 0x00000537u, 4, 0x12345, 134 0, 0, 0x00012537u}, 135 {"rv PCREL_HI20", KIT_ARCH_RV64, R_RV_PCREL_HI20, 0x00000517u, 4, 0x13345, 136 0, 0x1000, 0x00012517u}, 137 {"rv GOT_HI20", KIT_ARCH_RV64, R_RV_GOT_HI20, 0x00000517u, 4, 0x13345, 0, 138 0x1000, 0x00012517u}, 139 {"rv TLS_GOT_HI20", KIT_ARCH_RV64, R_RV_TLS_GOT_HI20, 0x00000517u, 4, 140 0x13345, 0, 0x1000, 0x00012517u}, 141 {"rv LO12_I", KIT_ARCH_RV64, R_RV_LO12_I, 0x00000013u, 4, 0x12345, 0, 0, 142 0x34500013u}, 143 {"rv TPREL_LO12_I", KIT_ARCH_RV64, R_RV_TPREL_LO12_I, 0x00000013u, 4, 144 0x12345, 0, 0, 0x34500013u}, 145 {"rv LO12_S", KIT_ARCH_RV64, R_RV_LO12_S, 0x00000023u, 4, 0x12345, 0, 0, 146 0x340002a3u}, 147 {"rv TPREL_LO12_S", KIT_ARCH_RV64, R_RV_TPREL_LO12_S, 0x00000023u, 4, 148 0x12345, 0, 0, 0x340002a3u}, 149 {"rv BRANCH", KIT_ARCH_RV64, R_RV_BRANCH, 0x00000063u, 4, 0x1100, 0, 0x1000, 150 0x10000063u}, 151 {"rv JAL", KIT_ARCH_RV64, R_RV_JAL, 0x0000006fu, 4, 0x5100, 0, 0x1000, 152 0x1000406fu}, 153 {"rv CALL", KIT_ARCH_RV64, R_RV_CALL, 0x000080e700000097ull, 8, 0x100000, 0, 154 0x1000, 0x000080e7000ff097ull}, 155 {"rv PLT32", KIT_ARCH_RV64, R_PLT32, 0x000080e700000097ull, 8, 0x100000, 0, 156 0x1000, 0x000080e7000ff097ull}, 157 {"rv RVC_BRANCH", KIT_ARCH_RV64, R_RV_RVC_BRANCH, 0xc001u, 2, 0x1080, 0, 158 0x1000, 0xc041u}, 159 {"rv RVC_JUMP", KIT_ARCH_RV64, R_RV_RVC_JUMP, 0xa001u, 2, 0x1400, 0, 0x1000, 160 0xa101u}, 161 /* ---- RISC-V relaxation markers (no bytes patched) ---- */ 162 {"rv RELAX", KIT_ARCH_RV64, R_RV_RELAX, 0xdeadbeefu, 4, 0x1000, 0, 0x2000, 163 0xdeadbeefu}, 164 {"rv TPREL_ADD", KIT_ARCH_RV64, R_RV_TPREL_ADD, 0xdeadbeefu, 4, 0x1000, 0, 165 0x2000, 0xdeadbeefu}, 166 /* ---- RISC-V neutral data-word arms (kept in obj core) ---- */ 167 {"rv ADD32", KIT_ARCH_RV64, R_ADD32, 0x00000010u, 4, 0x20, 0, 0, 168 0x00000030u}, 169 {"rv SUB32", KIT_ARCH_RV64, R_SUB32, 0x00000030u, 4, 0x10, 0, 0, 170 0x00000020u}, 171 {"rv SET8", KIT_ARCH_RV64, R_ABS8, 0x00u, 1, 0x2a, 0, 0, 0x2au}, 172 }; 173 174 static KitCompiler* compiler_for(KitArchKind arch) { 175 static KitCompiler* aa64 = NULL; 176 static KitCompiler* x64 = NULL; 177 static KitCompiler* rv64 = NULL; 178 KitCompiler** slot = arch == KIT_ARCH_ARM_64 ? &aa64 179 : arch == KIT_ARCH_X86_64 ? &x64 180 : &rv64; 181 if (!*slot) { 182 KitTargetSpec t = kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF); 183 if (kit_unit_compiler_new(&g_u, t, slot) != KIT_OK || !*slot) { 184 fprintf(stderr, "compiler_new failed for arch=%d\n", (int)arch); 185 exit(2); 186 } 187 } 188 return *slot; 189 } 190 191 static void check_x64_tlsld_relax(void) { 192 u8 got[12] = {0x48u, 0x8du, 0x3du, 0x00u, 0x00u, 0x00u, 193 0x00u, 0xe8u, 0x00u, 0x00u, 0x00u, 0x00u}; 194 static const u8 want[12] = {0x64u, 0x48u, 0x8bu, 0x04u, 0x25u, 0x00u, 195 0x00u, 0x00u, 0x00u, 0x90u, 0x90u, 0x90u}; 196 link_reloc_apply(compiler_for(KIT_ARCH_X86_64), R_X64_TLSLD, got + 3, 0, -4, 197 0); 198 EXPECT(memcmp(got, want, sizeof got) == 0, "x64 TLSLD relaxation mismatch"); 199 } 200 201 static void check_rv_tlsgd_relax(void) { 202 u8 got[16] = {0x17u, 0x05u, 0x00u, 0x00u, 0x13u, 0x05u, 0x05u, 0x00u, 203 0x97u, 0x00u, 0x00u, 0x00u, 0xe7u, 0x80u, 0x00u, 0x00u}; 204 static const u8 want[16] = { 205 0x37u, 0x25u, 0x01u, 0x00u, 0x13u, 0x05u, 0x55u, 0x34u, 206 0x33u, 0x05u, 0x45u, 0x00u, 0x13u, 0x00u, 0x00u, 0x00u}; 207 link_reloc_apply(compiler_for(KIT_ARCH_RV64), R_RV_TLS_GD_HI20, got, 208 0x12345, 0, 0); 209 EXPECT(memcmp(got, want, sizeof got) == 0, 210 "RISC-V TLS_GD relaxation mismatch"); 211 } 212 213 static void check_rv_tlsgd_relax_compressed_gap(void) { 214 u8 got[20] = { 215 0x97u, 0x05u, 0x00u, 0x00u, /* auipc a1, %tlsgd_hi */ 216 0x93u, 0x85u, 0x05u, 0x00u, /* mv a1, a1 */ 217 0x2au, 0x89u, /* c.mv s2, a0 */ 218 0x2eu, 0x85u, /* c.mv a0, a1 */ 219 0x97u, 0x00u, 0x00u, 0x00u, /* auipc ra, __tls_get_addr */ 220 0xe7u, 0x80u, 0x00u, 0x00u /* jalr ra */ 221 }; 222 static const u8 want[20] = { 223 0xb7u, 0x25u, 0x01u, 0x00u, /* lui a1, %tprel_hi */ 224 0x93u, 0x85u, 0x55u, 0x34u, /* addi a1, a1, %tprel_lo */ 225 0x2au, 0x89u, /* c.mv s2, a0 */ 226 0x2eu, 0x85u, /* c.mv a0, a1 */ 227 0x33u, 0x05u, 0x45u, 0x00u, /* add a0, a0, tp */ 228 0x13u, 0x00u, 0x00u, 0x00u /* nop */ 229 }; 230 link_reloc_apply(compiler_for(KIT_ARCH_RV64), R_RV_TLS_GD_HI20, got, 231 0x12345, 0, 0); 232 EXPECT(memcmp(got, want, sizeof got) == 0, 233 "RISC-V TLS_GD compressed-gap relaxation mismatch"); 234 } 235 236 int main(void) { 237 size_t i; 238 int capture = getenv("KIT_RELOC_APPLY_CAPTURE") != NULL; 239 240 kit_unit_init(&g_u); 241 242 for (i = 0; i < sizeof kCases / sizeof kCases[0]; ++i) { 243 const ApplyCase* tc = &kCases[i]; 244 u8 buf[8] = {0}; 245 u64 got = 0; 246 u32 b; 247 memcpy(buf, &tc->in, tc->nbytes); 248 link_reloc_apply(compiler_for(tc->arch), tc->kind, buf, tc->S, tc->A, 249 tc->P); 250 for (b = 0; b < tc->nbytes; ++b) got |= (u64)buf[b] << (8u * b); 251 252 if (capture) { 253 printf(" /* %-32s */ 0x%016llxull,\n", tc->name, 254 (unsigned long long)got); 255 continue; 256 } 257 EXPECT(got == tc->want, "%s: got=0x%016llx want=0x%016llx", tc->name, 258 (unsigned long long)got, (unsigned long long)tc->want); 259 } 260 261 check_x64_tlsld_relax(); 262 check_rv_tlsgd_relax(); 263 check_rv_tlsgd_relax_compressed_gap(); 264 265 if (capture) return 0; 266 kit_unit_summary(&g_u, "reloc_apply_test"); 267 return kit_unit_status(&g_u); 268 }