kit

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

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 }