reloc_desc_test.c (9675B)
1 /* Relocation-descriptor migration guard (doc/plan/RELOC.md, WS-B). 2 * 3 * The per-arch RelocDesc table replaced the generic reloc_width / 4 * reloc_uses_got / reloc_is_tls_got switches and the per-arch 5 * LinkArchDesc.is_branch / is_got_load / is_tlvp / is_direct_page / 6 * needs_jit_call_stub hooks. This test pins behavioural equivalence: for 7 * every RelocKind, under every backend arch, reloc_desc() and the 8 * reloc_kind_* predicates must reproduce the frozen pre-refactor behaviour 9 * captured by the oracle_* functions below. 10 * 11 * The oracle_* bodies are VERBATIM snapshots of the deleted code — do not 12 * "improve" them; they are the spec the descriptor table must match. 13 * 14 * Coverage of per-arch *ownership* of non-classifier kinds (a kind sized 15 * under the wrong arch) is left to the bootstrap / smoke link oracles, which 16 * patch every kind a backend actually emits — the unit guard here pins the 17 * width of every row that exists, the classification of every kind, and that 18 * no previously-sized kind lost its descriptor. */ 19 20 #include <kit/cg.h> 21 #include <kit/core.h> 22 23 #include "core/core.h" 24 #include "lib/kit_unit.h" 25 #include "link/link_reloc_desc.h" 26 #include "obj/obj.h" 27 #include "obj/reloc.h" 28 29 static KitUnit g_u; 30 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 31 32 /* ============================================================ 33 * Frozen pre-refactor behaviour (the migration guard) 34 * ============================================================ */ 35 36 #define ORACLE_RV_ULEB128_NOMINAL_WIDTH 1u 37 38 /* Verbatim snapshot of the former reloc_width() (arch-independent). */ 39 static u8 oracle_width(RelocKind k) { 40 switch (k) { 41 case R_ABS32: 42 case R_REL32: 43 case R_PC32: 44 case R_GOT32: 45 case R_PLT32: 46 case R_X64_PLT32: 47 case R_X64_32S: 48 case R_X64_TPOFF32: 49 case R_X64_GOTPCREL: 50 case R_X64_GOTPCRELX: 51 case R_X64_REX_GOTPCRELX: 52 case R_X64_GOTPC32: 53 case R_X64_GOTTPOFF: 54 return 4; 55 case R_ABS64: 56 case R_REL64: 57 case R_PC64: 58 case R_TPOFF64: 59 case R_X64_GLOB_DAT: 60 case R_X64_JUMP_SLOT: 61 case R_X64_RELATIVE: 62 return 8; 63 case R_ABS8: 64 case R_X64_PC8: 65 return 1; 66 case R_ABS16: 67 case R_PREL16: 68 return 2; 69 case R_AARCH64_JUMP26: 70 case R_AARCH64_CALL26: 71 case R_AARCH64_CONDBR19: 72 case R_AARCH64_TSTBR14: 73 case R_AARCH64_LD_PREL_LO19: 74 case R_AARCH64_ADR_PREL_LO21: 75 case R_AARCH64_ADR_PREL_PG_HI21: 76 case R_AARCH64_ADR_PREL_PG_HI21_NC: 77 case R_AARCH64_ADD_ABS_LO12_NC: 78 case R_AARCH64_LDST8_ABS_LO12_NC: 79 case R_AARCH64_LDST16_ABS_LO12_NC: 80 case R_AARCH64_LDST32_ABS_LO12_NC: 81 case R_AARCH64_LDST64_ABS_LO12_NC: 82 case R_AARCH64_LDST128_ABS_LO12_NC: 83 case R_AARCH64_ADR_GOT_PAGE: 84 case R_AARCH64_LD64_GOT_LO12_NC: 85 case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: 86 case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: 87 case R_AARCH64_TLSLE_ADD_TPREL_HI12: 88 case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: 89 case R_AARCH64_TLVP_LOAD_PAGE21: 90 case R_AARCH64_TLVP_LOAD_PAGEOFF12: 91 return 4; 92 case R_RV_HI20: 93 case R_RV_LO12_I: 94 case R_RV_LO12_S: 95 case R_RV_BRANCH: 96 case R_RV_JAL: 97 case R_RV_PCREL_HI20: 98 case R_RV_PCREL_LO12_I: 99 case R_RV_PCREL_LO12_S: 100 case R_RV_GOT_HI20: 101 case R_RV_TLS_GOT_HI20: 102 case R_RV_TPREL_HI20: 103 case R_RV_TPREL_LO12_I: 104 case R_RV_TPREL_LO12_S: 105 return 4; 106 case R_RV_CALL: 107 return 8; 108 case R_RV_RVC_BRANCH: 109 case R_RV_RVC_JUMP: 110 return 2; 111 case R_RV_RELAX: 112 case R_RV_TPREL_ADD: 113 return 4; 114 case R_ADD8: 115 case R_SUB8: 116 case R_SUB6: 117 case R_SET6: 118 return 1; 119 case R_ADD16: 120 case R_SUB16: 121 return 2; 122 case R_ADD32: 123 case R_SUB32: 124 return 4; 125 case R_ADD64: 126 case R_SUB64: 127 return 8; 128 case R_SET_ULEB128: 129 case R_SUB_ULEB128: 130 return ORACLE_RV_ULEB128_NOMINAL_WIDTH; 131 case R_COFF_SECREL: 132 case R_COFF_ADDR32NB: 133 return 4; 134 case R_COFF_SECTION: 135 return 2; 136 case R_COFF_AARCH64_SECREL_LOW12A: 137 case R_COFF_AARCH64_SECREL_HIGH12A: 138 return 4; 139 default: 140 return 0; 141 } 142 } 143 144 /* Per-arch classification snapshots. The deleted reloc_uses_got / 145 * reloc_is_tls_got were arch-independent switches; they partition cleanly 146 * by arch (each case belongs to exactly one backend), so the equivalent 147 * arch-scoped predicate is the per-arch slice below. branch / got_load / 148 * tlvp / direct_page mirror the former per-arch LinkArchDesc hooks (NULL 149 * hook == always 0). */ 150 151 /* RELOC_USES_GOT set (direct GOT load): the Mach-O is_got_load hook for 152 * aa64/x64, and the GOT-allocating subset of reloc_uses_got for rv. */ 153 static int oracle_aa64_got_use(RelocKind k) { 154 return k == R_AARCH64_ADR_GOT_PAGE || k == R_AARCH64_LD64_GOT_LO12_NC; 155 } 156 static int oracle_x64_got_use(RelocKind k) { 157 return k == R_X64_GOTPCREL || k == R_X64_GOTPCRELX || 158 k == R_X64_REX_GOTPCRELX; 159 } 160 static int oracle_rv_got_use(RelocKind k) { return k == R_RV_GOT_HI20; } 161 162 /* RELOC_IS_TLS_GOT set (TLS Initial-Exec GOT slot). */ 163 static int oracle_aa64_tls_got(RelocKind k) { 164 return k == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || 165 k == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; 166 } 167 static int oracle_x64_tls_got(RelocKind k) { return k == R_X64_GOTTPOFF; } 168 static int oracle_rv_tls_got(RelocKind k) { return k == R_RV_TLS_GOT_HI20; } 169 170 /* needs_jit_call_stub / is_branch_reloc. */ 171 static int oracle_aa64_branch(RelocKind k) { 172 return k == R_AARCH64_CALL26 || k == R_AARCH64_JUMP26; 173 } 174 static int oracle_x64_branch(RelocKind k) { 175 return k == R_X64_PLT32 || k == R_PLT32; 176 } 177 static int oracle_rv_branch(RelocKind k) { 178 return k == R_RV_CALL || k == R_PLT32; 179 } 180 181 /* is_tlvp_reloc (Mach-O aa64 only). */ 182 static int oracle_aa64_tlvp(RelocKind k) { 183 return k == R_AARCH64_TLVP_LOAD_PAGE21 || k == R_AARCH64_TLVP_LOAD_PAGEOFF12; 184 } 185 186 /* is_direct_page_reloc (Mach-O aa64 only). */ 187 static int oracle_aa64_direct_page(RelocKind k) { 188 switch (k) { 189 case R_AARCH64_ADR_PREL_PG_HI21: 190 case R_AARCH64_ADR_PREL_PG_HI21_NC: 191 case R_AARCH64_ADD_ABS_LO12_NC: 192 case R_AARCH64_LDST8_ABS_LO12_NC: 193 case R_AARCH64_LDST16_ABS_LO12_NC: 194 case R_AARCH64_LDST32_ABS_LO12_NC: 195 case R_AARCH64_LDST64_ABS_LO12_NC: 196 case R_AARCH64_LDST128_ABS_LO12_NC: 197 return 1; 198 default: 199 return 0; 200 } 201 } 202 203 static int zero_oracle(RelocKind k) { 204 (void)k; 205 return 0; 206 } 207 208 typedef struct ArchOracle { 209 const char* name; 210 KitArchKind arch; 211 int (*got_use)(RelocKind); 212 int (*tls_got)(RelocKind); 213 int (*branch)(RelocKind); 214 int (*tlvp)(RelocKind); 215 int (*direct_page)(RelocKind); 216 } ArchOracle; 217 218 static const ArchOracle kArchOracles[] = { 219 {"aarch64", KIT_ARCH_ARM_64, oracle_aa64_got_use, oracle_aa64_tls_got, 220 oracle_aa64_branch, oracle_aa64_tlvp, oracle_aa64_direct_page}, 221 {"x86_64", KIT_ARCH_X86_64, oracle_x64_got_use, oracle_x64_tls_got, 222 oracle_x64_branch, zero_oracle, zero_oracle}, 223 {"rv64", KIT_ARCH_RV64, oracle_rv_got_use, oracle_rv_tls_got, 224 oracle_rv_branch, zero_oracle, zero_oracle}, 225 {"rv32", KIT_ARCH_RV32, oracle_rv_got_use, oracle_rv_tls_got, 226 oracle_rv_branch, zero_oracle, zero_oracle}, 227 }; 228 229 /* Last RelocKind enum value; the enum is contiguous from R_NONE = 0. */ 230 #define RELOC_KIND_LAST R_COFF_ADDR32NB 231 232 static KitCompiler* new_compiler(KitArchKind arch) { 233 KitTargetSpec t = kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF); 234 KitCompiler* c = NULL; 235 if (arch == KIT_ARCH_RV32) { 236 t.ptr_size = 4; 237 t.ptr_align = 4; 238 } 239 if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) { 240 fprintf(stderr, "compiler_new failed for arch=%d\n", (int)arch); 241 exit(2); 242 } 243 return c; 244 } 245 246 int main(void) { 247 size_t a; 248 int covered[RELOC_KIND_LAST + 1]; 249 int kk; 250 251 kit_unit_init(&g_u); 252 for (kk = 0; kk <= (int)RELOC_KIND_LAST; ++kk) covered[kk] = 0; 253 254 for (a = 0; a < sizeof kArchOracles / sizeof kArchOracles[0]; ++a) { 255 const ArchOracle* ao = &kArchOracles[a]; 256 KitCompiler* c = new_compiler(ao->arch); 257 for (kk = 0; kk <= (int)RELOC_KIND_LAST; ++kk) { 258 RelocKind k = (RelocKind)kk; 259 const RelocDesc* d = reloc_desc(c, k); 260 261 /* Width parity wherever a row exists; coverage tracked separately. */ 262 if (d) { 263 covered[kk] = 1; 264 EXPECT(d->width == oracle_width(k), "%s: width(%d) = %u, want %u", 265 ao->name, kk, (unsigned)d->width, (unsigned)oracle_width(k)); 266 } 267 268 /* Classification parity, strict per arch (arch-scoped both sides). */ 269 EXPECT(reloc_kind_is_got_load(c, k) == ao->got_use(k), 270 "%s: is_got_load(%d) mismatch", ao->name, kk); 271 EXPECT(reloc_kind_is_tls_got(c, k) == ao->tls_got(k), 272 "%s: is_tls_got(%d) mismatch", ao->name, kk); 273 EXPECT(reloc_kind_uses_got(c, k) == (ao->got_use(k) || ao->tls_got(k)), 274 "%s: uses_got(%d) mismatch", ao->name, kk); 275 EXPECT(reloc_kind_is_branch(c, k) == ao->branch(k), 276 "%s: is_branch(%d) mismatch", ao->name, kk); 277 EXPECT(reloc_kind_is_tlvp(c, k) == ao->tlvp(k), 278 "%s: is_tlvp(%d) mismatch", ao->name, kk); 279 EXPECT(reloc_kind_is_direct_page(c, k) == ao->direct_page(k), 280 "%s: is_direct_page(%d) mismatch", ao->name, kk); 281 } 282 } 283 284 /* No previously-sized kind lost its descriptor: every kind the old 285 * reloc_width() sized must resolve under at least one backend arch. */ 286 for (kk = 0; kk <= (int)RELOC_KIND_LAST; ++kk) { 287 if (oracle_width((RelocKind)kk) != 0) 288 EXPECT(covered[kk], "kind %d had width %u but resolves under no arch", kk, 289 (unsigned)oracle_width((RelocKind)kk)); 290 } 291 292 kit_unit_summary(&g_u, "reloc_desc_test"); 293 return kit_unit_status(&g_u); 294 }