kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }