rv64_smoke_test.c (42084B)
1 /* RV64 emulator smoke test. 2 * 3 * Builds a tiny statically-linked rv64 ELF64 in memory whose _start 4 * does: 5 * 6 * addi a0, zero, 42 # exit code 7 * addi a7, zero, 94 # SYS_exit_group 8 * ecall 9 * 10 * Runs it through kit_emu_run and asserts the lifted/JIT path exits 11 * with code 42. 12 * 13 * This exercises: 14 * - the ELF64 loader (header + program-header validation, PT_LOAD 15 * placement, argv/envp/auxv stack layout) 16 * - the shared RV64 ArchDecodeOps path (ADDI, ECALL) 17 * - the syscall handler (SYS_exit_group) 18 * - the RV64 ArchEmuOps lifter and host JIT dispatch path. */ 19 20 #include <kit/compile.h> 21 #include <kit/core.h> 22 #include <kit/emu.h> 23 #include <kit/jit.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <sys/mman.h> 28 #include <unistd.h> 29 #if defined(__APPLE__) 30 #include <mach/mach.h> 31 #include <mach/mach_vm.h> 32 #define XM_DUAL_APPLE 1 33 #else 34 #define XM_DUAL_APPLE 0 35 #endif 36 #if defined(__linux__) 37 #include <sys/syscall.h> 38 #define XM_DUAL_LINUX 1 39 #else 40 #define XM_DUAL_LINUX 0 41 #endif 42 43 /* Internal headers used only for header-only helpers (no internal link symbols 44 * are referenced — this test drives the emulator entirely through the public 45 * kit_emu_* API, so it links the public archive): rv64 instruction encoders 46 * (static inline) and ELF64 layout constants. The accompanying white-box unit 47 * tests for the decoder / address space / syscall units live in 48 * rv64_vm_unit_test.c, which links the library objects directly. */ 49 #include "arch/riscv/isa.h" 50 #include "core/core.h" 51 #include "lib/kit_unit.h" 52 #include "obj/elf/elf.h" 53 54 /* Shared test context replaces the per-file heap/diag/counter globals; 55 * EXPECT aliases CU_EXPECT so the call sites below are unchanged. */ 56 static KitUnit g_u; 57 #define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__) 58 59 static int xm_to_posix(int p) { 60 int q = 0; 61 if (p & KIT_PROT_READ) q |= PROT_READ; 62 if (p & KIT_PROT_WRITE) q |= PROT_WRITE; 63 if (p & KIT_PROT_EXEC) q |= PROT_EXEC; 64 return q; 65 } 66 67 typedef struct XmTok { 68 void* w; 69 void* r; 70 size_t n; 71 } XmTok; 72 73 static KitStatus xm_reserve_single(size_t n, KitExecMemRegion* out) { 74 void* m = 75 mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 76 if (m == MAP_FAILED) return KIT_NOMEM; 77 out->write = m; 78 out->runtime = m; 79 out->size = n; 80 out->token = NULL; 81 return KIT_OK; 82 } 83 84 static KitStatus xm_reserve(void* user, size_t n, int prot, 85 KitExecMemRegion* out) { 86 (void)user; 87 if (!out || !n) return KIT_INVALID; 88 if (!(prot & KIT_PROT_EXEC)) return xm_reserve_single(n, out); 89 #if XM_DUAL_APPLE 90 { 91 void* w = 92 mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 93 mach_vm_address_t r = 0; 94 vm_prot_t cur = 0, max = 0; 95 XmTok* tok; 96 if (w == MAP_FAILED) return KIT_NOMEM; 97 if (mach_vm_remap(mach_task_self(), &r, (mach_vm_size_t)n, 0, 98 VM_FLAGS_ANYWHERE, mach_task_self(), 99 (mach_vm_address_t)(uintptr_t)w, FALSE, &cur, &max, 100 VM_INHERIT_NONE) != KERN_SUCCESS) { 101 munmap(w, n); 102 return KIT_NOMEM; 103 } 104 if (mprotect((void*)(uintptr_t)r, n, PROT_READ) != 0) { 105 munmap((void*)(uintptr_t)r, n); 106 munmap(w, n); 107 return KIT_NOMEM; 108 } 109 tok = (XmTok*)malloc(sizeof(*tok)); 110 if (!tok) { 111 munmap((void*)(uintptr_t)r, n); 112 munmap(w, n); 113 return KIT_NOMEM; 114 } 115 tok->w = w; 116 tok->r = (void*)(uintptr_t)r; 117 tok->n = n; 118 out->write = w; 119 out->runtime = (void*)(uintptr_t)r; 120 out->size = n; 121 out->token = tok; 122 return KIT_OK; 123 } 124 #elif XM_DUAL_LINUX 125 { 126 int fd = (int)syscall(SYS_memfd_create, "kit-emu-jit-test", 0u); 127 void *w, *r; 128 XmTok* tok; 129 if (fd < 0) return KIT_NOMEM; 130 if (ftruncate(fd, (off_t)n) != 0) { 131 close(fd); 132 return KIT_NOMEM; 133 } 134 w = mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 135 if (w == MAP_FAILED) { 136 close(fd); 137 return KIT_NOMEM; 138 } 139 r = mmap(NULL, n, PROT_READ, MAP_SHARED, fd, 0); 140 close(fd); 141 if (r == MAP_FAILED) { 142 munmap(w, n); 143 return KIT_NOMEM; 144 } 145 tok = (XmTok*)malloc(sizeof(*tok)); 146 if (!tok) { 147 munmap(r, n); 148 munmap(w, n); 149 return KIT_NOMEM; 150 } 151 tok->w = w; 152 tok->r = r; 153 tok->n = n; 154 out->write = w; 155 out->runtime = r; 156 out->size = n; 157 out->token = tok; 158 return KIT_OK; 159 } 160 #else 161 return xm_reserve_single(n, out); 162 #endif 163 } 164 165 static KitStatus xm_protect(void* user, void* addr, size_t n, int prot) { 166 (void)user; 167 return mprotect(addr, n, xm_to_posix(prot)) == 0 ? KIT_OK : KIT_IO; 168 } 169 170 static void xm_release(void* user, KitExecMemRegion* r) { 171 (void)user; 172 if (!r || !r->size) return; 173 if (r->token) { 174 XmTok* tok = (XmTok*)r->token; 175 if (tok->r && tok->r != tok->w) munmap(tok->r, tok->n); 176 if (tok->w) munmap(tok->w, tok->n); 177 free(tok); 178 } else if (r->write) { 179 munmap(r->write, r->size); 180 } 181 memset(r, 0, sizeof(*r)); 182 } 183 184 static void xm_flush(void* user, void* addr, size_t n) { 185 (void)user; 186 #if defined(__aarch64__) || defined(__arm__) || defined(__riscv) 187 __builtin___clear_cache((char*)addr, (char*)addr + n); 188 #else 189 (void)addr; 190 (void)n; 191 #endif 192 } 193 194 static KitExecMem g_execmem = { 195 16 * 1024, xm_reserve, xm_protect, xm_release, xm_flush, NULL, 196 }; 197 198 static KitCompiler* new_host_compiler(void) { 199 KitArchKind arch; 200 KitOSKind os; 201 KitObjFmt obj; 202 KitTargetSpec t; 203 KitCompiler* c = NULL; 204 #if defined(__x86_64__) || defined(_M_X64) 205 arch = KIT_ARCH_X86_64; 206 #elif defined(__aarch64__) || defined(_M_ARM64) 207 arch = KIT_ARCH_ARM_64; 208 #elif defined(__riscv) && __riscv_xlen == 64 209 arch = KIT_ARCH_RV64; 210 #else 211 return NULL; 212 #endif 213 #if defined(__APPLE__) 214 os = KIT_OS_MACOS; 215 obj = KIT_OBJ_MACHO; 216 #elif defined(__linux__) 217 os = KIT_OS_LINUX; 218 obj = KIT_OBJ_ELF; 219 #else 220 return NULL; 221 #endif 222 t = kit_unit_target(arch, os, obj); 223 if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) { 224 fprintf(stderr, "host compiler_new failed\n"); 225 exit(2); 226 } 227 return c; 228 } 229 230 /* ============================================================ 231 * Minimal RV64 ELF64 builder 232 * ============================================================ */ 233 234 /* Writes a u16 / u32 / u64 LE into a byte buffer at offset `off`. */ 235 static void put16(unsigned char* b, size_t off, unsigned v) { 236 b[off + 0] = (unsigned char)v; 237 b[off + 1] = (unsigned char)(v >> 8); 238 } 239 static void put32(unsigned char* b, size_t off, unsigned v) { 240 b[off + 0] = (unsigned char)v; 241 b[off + 1] = (unsigned char)(v >> 8); 242 b[off + 2] = (unsigned char)(v >> 16); 243 b[off + 3] = (unsigned char)(v >> 24); 244 } 245 static void put64(unsigned char* b, size_t off, uint64_t v) { 246 put32(b, off, (unsigned)v); 247 put32(b, off + 4, (unsigned)(v >> 32)); 248 } 249 250 static void put_phdr(unsigned char* b, size_t off, uint32_t type, 251 uint32_t flags, uint64_t file_off, uint64_t vaddr, 252 uint64_t filesz, uint64_t memsz, uint64_t align) { 253 put32(b, off + 0, type); 254 put32(b, off + 4, flags); 255 put64(b, off + 8, file_off); 256 put64(b, off + 16, vaddr); 257 put64(b, off + 24, vaddr); 258 put64(b, off + 32, filesz); 259 put64(b, off + 40, memsz); 260 put64(b, off + 48, align); 261 } 262 263 static void put_dyn(unsigned char* b, size_t off, uint64_t tag, uint64_t val) { 264 put64(b, off + 0, tag); 265 put64(b, off + 8, val); 266 } 267 268 static void put_sym(unsigned char* b, size_t off, uint32_t name, uint8_t info, 269 uint16_t shndx, uint64_t value, uint64_t size) { 270 put32(b, off + 0, name); 271 b[off + 4] = info; 272 b[off + 5] = 0; 273 put16(b, off + 6, shndx); 274 put64(b, off + 8, value); 275 put64(b, off + 16, size); 276 } 277 278 static void put_rela(unsigned char* b, size_t off, uint64_t r_offset, 279 uint64_t r_info, int64_t addend) { 280 put64(b, off + 0, r_offset); 281 put64(b, off + 8, r_info); 282 put64(b, off + 16, (uint64_t)addend); 283 } 284 285 static int64_t pcrel_delta(uint64_t from, uint64_t to) { 286 if (to >= from) return (int64_t)(to - from); 287 return -(int64_t)(from - to); 288 } 289 290 static uint32_t rv_pcrel_hi(uint64_t from, uint64_t to) { 291 int64_t d = pcrel_delta(from, to); 292 return (uint32_t)((d + 0x800) >> 12) & 0xfffffu; 293 } 294 295 static int32_t rv_pcrel_lo(uint64_t from, uint64_t to) { 296 int64_t d = pcrel_delta(from, to); 297 int64_t hi = (d + 0x800) >> 12; 298 return (int32_t)(d - (hi << 12)); 299 } 300 301 /* Build a static rv64 ELF: ehdr + 1 phdr + text. The text segment is 302 * page-aligned at virtual address 0x10000 and contains the three 303 * instructions described in the file header. Returns the buffer (must 304 * be freed). */ 305 static unsigned char* build_minimal_elf(size_t* out_len) { 306 /* Layout: 307 * [0..63] ELF64 ehdr 308 * [64..119] one PT_LOAD phdr (size 56) 309 * [120..] pad to page boundary 310 * page-aligned: .text bytes (3 instructions = 12 bytes) 311 * 312 * We use a 4 KiB page; the .text starts at file offset 0x1000 and 313 * VA 0x11000 (so the loader's lo_va == 0x11000 unless we choose a 314 * lower vaddr for the PT_LOAD). 315 * 316 * Easier: have PT_LOAD cover [0, end_of_text) at VA 0x10000, file 317 * offset 0, filesz = end-of-text. e_entry points at the start of 318 * .text. .text begins at file offset 0x1000 (page-aligned). */ 319 enum { 320 PAGE = 0x1000u, 321 BASE_VA = 0x10000ull, 322 TEXT_OFF = 0x1000u, 323 TEXT_LEN = 12u, 324 }; 325 size_t total = TEXT_OFF + TEXT_LEN; 326 unsigned char* b = (unsigned char*)calloc(1, total); 327 if (!b) return NULL; 328 329 /* ELF header — 64 bytes. */ 330 b[EI_MAG0] = ELFMAG0; 331 b[EI_MAG1] = ELFMAG1; 332 b[EI_MAG2] = ELFMAG2; 333 b[EI_MAG3] = ELFMAG3; 334 b[EI_CLASS] = ELFCLASS64; 335 b[EI_DATA] = ELFDATA2LSB; 336 b[EI_VERSION] = EV_CURRENT; 337 b[EI_OSABI] = ELFOSABI_NONE; 338 put16(b, 16, ET_EXEC); /* e_type */ 339 put16(b, 18, EM_RISCV); /* e_machine */ 340 put32(b, 20, EV_CURRENT); /* e_version */ 341 put64(b, 24, BASE_VA + TEXT_OFF); /* e_entry */ 342 put64(b, 32, 64); /* e_phoff */ 343 put64(b, 40, 0); /* e_shoff (none) */ 344 put32(b, 48, 0); /* e_flags */ 345 put16(b, 52, ELF64_EHDR_SIZE); /* e_ehsize */ 346 put16(b, 54, ELF64_PHDR_SIZE); /* e_phentsize */ 347 put16(b, 56, 1); /* e_phnum */ 348 put16(b, 58, 0); /* e_shentsize */ 349 put16(b, 60, 0); /* e_shnum */ 350 put16(b, 62, 0); /* e_shstrndx */ 351 352 /* PT_LOAD phdr — 56 bytes at offset 64. */ 353 put32(b, 64 + 0, PT_LOAD); /* p_type */ 354 put32(b, 64 + 4, PF_R | PF_X); /* p_flags */ 355 put64(b, 64 + 8, 0); /* p_offset */ 356 put64(b, 64 + 16, BASE_VA); /* p_vaddr */ 357 put64(b, 64 + 24, BASE_VA); /* p_paddr */ 358 put64(b, 64 + 32, total); /* p_filesz */ 359 put64(b, 64 + 40, total); /* p_memsz */ 360 put64(b, 64 + 48, PAGE); /* p_align */ 361 362 /* .text: addi a0,zero,42 ; addi a7,zero,94 ; ecall */ 363 put32(b, TEXT_OFF + 0, rv_addi(RV_A0, RV_ZERO, 42)); 364 put32(b, TEXT_OFF + 4, rv_addi(RV_A7, RV_ZERO, 94)); 365 put32(b, TEXT_OFF + 8, rv_ecall()); 366 367 *out_len = total; 368 return b; 369 } 370 371 /* Dynamic fixture for the intended emu loader surface: 372 * PT_INTERP + PT_DYNAMIC + DT_NEEDED + JUMP_SLOT import + PT_TLS. 373 * 374 * The import resolver is expected to fill `import_add_got` with a 375 * guest-callable thunk for import_add(a0). The TLS setup is expected to seed tp 376 * so that ld t1, 0(tp) reads the PT_TLS initializer 11. The guest exits 31 377 * + 11. */ 378 static unsigned char* build_dynamic_import_tls_elf(size_t* out_len) { 379 enum { 380 PAGE = 0x1000u, 381 BASE_VA = 0x10000ull, 382 PHNUM = 5u, 383 TEXT_OFF = 0x1000u, 384 INTERP_OFF = 0x1100u, 385 DYNSTR_OFF = 0x1180u, 386 DYNSYM_OFF = 0x1200u, 387 RELA_OFF = 0x1300u, 388 DYNAMIC_OFF = 0x2000u, 389 DATA_OFF = 0x2100u, 390 TLS_OFF = 0x2200u, 391 TOTAL = 0x2300u, 392 }; 393 const uint64_t text_va = BASE_VA + TEXT_OFF; 394 const uint64_t interp_va = BASE_VA + INTERP_OFF; 395 const uint64_t dynstr_va = BASE_VA + DYNSTR_OFF; 396 const uint64_t dynsym_va = BASE_VA + DYNSYM_OFF; 397 const uint64_t rela_va = BASE_VA + RELA_OFF; 398 const uint64_t dynamic_va = BASE_VA + DYNAMIC_OFF; 399 const uint64_t got_va = BASE_VA + DATA_OFF; 400 const uint64_t tls_va = BASE_VA + TLS_OFF; 401 const char interp[] = "/kit-test-ld.so"; 402 const char needed[] = "libkit-emu-test.so"; 403 const char import_name[] = "import_add"; 404 const size_t dynstr_needed_off = 1u; 405 const size_t dynstr_import_off = 1u + sizeof(needed); 406 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 407 unsigned char* ds; 408 size_t dynstr_len; 409 410 if (!b) return NULL; 411 412 b[EI_MAG0] = ELFMAG0; 413 b[EI_MAG1] = ELFMAG1; 414 b[EI_MAG2] = ELFMAG2; 415 b[EI_MAG3] = ELFMAG3; 416 b[EI_CLASS] = ELFCLASS64; 417 b[EI_DATA] = ELFDATA2LSB; 418 b[EI_VERSION] = EV_CURRENT; 419 b[EI_OSABI] = ELFOSABI_LINUX; 420 put16(b, 16, ET_EXEC); 421 put16(b, 18, EM_RISCV); 422 put32(b, 20, EV_CURRENT); 423 put64(b, 24, text_va); 424 put64(b, 32, ELF64_EHDR_SIZE); 425 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 426 put16(b, 52, ELF64_EHDR_SIZE); 427 put16(b, 54, ELF64_PHDR_SIZE); 428 put16(b, 56, PHNUM); 429 430 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 431 0x1400u, 0x1400u, PAGE); 432 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DYNAMIC_OFF, 433 dynamic_va, TLS_OFF + 8u - DYNAMIC_OFF, TLS_OFF + 8u - DYNAMIC_OFF, 434 PAGE); 435 put_phdr(b, 64 + 2u * ELF64_PHDR_SIZE, PT_INTERP, PF_R, INTERP_OFF, interp_va, 436 sizeof(interp), sizeof(interp), 1u); 437 put_phdr(b, 64 + 3u * ELF64_PHDR_SIZE, PT_DYNAMIC, PF_R | PF_W, DYNAMIC_OFF, 438 dynamic_va, 10u * ELF64_DYN_SIZE, 10u * ELF64_DYN_SIZE, 8u); 439 put_phdr(b, 64 + 4u * ELF64_PHDR_SIZE, PT_TLS, PF_R, TLS_OFF, tls_va, 8u, 8u, 440 8u); 441 442 put32(b, TEXT_OFF + 0u, rv_auipc(RV_T0, rv_pcrel_hi(text_va, got_va))); 443 put32(b, TEXT_OFF + 4u, rv_ld(RV_T0, RV_T0, rv_pcrel_lo(text_va, got_va))); 444 put32(b, TEXT_OFF + 8u, rv_addi(RV_A0, RV_ZERO, 31)); 445 put32(b, TEXT_OFF + 12u, rv_jalr(RV_RA, RV_T0, 0)); 446 put32(b, TEXT_OFF + 16u, rv_ld(RV_T1, RV_TP, 0)); 447 put32(b, TEXT_OFF + 20u, rv_add(RV_A0, RV_A0, RV_T1)); 448 put32(b, TEXT_OFF + 24u, rv_addi(RV_A7, RV_ZERO, 94)); 449 put32(b, TEXT_OFF + 28u, rv_ecall()); 450 451 memcpy(b + INTERP_OFF, interp, sizeof(interp)); 452 ds = b + DYNSTR_OFF; 453 ds[0] = 0; 454 memcpy(ds + dynstr_needed_off, needed, sizeof(needed)); 455 memcpy(ds + dynstr_import_off, import_name, sizeof(import_name)); 456 dynstr_len = dynstr_import_off + sizeof(import_name); 457 458 put_sym(b, DYNSYM_OFF, 0, 0, SHN_UNDEF, 0, 0); 459 put_sym(b, DYNSYM_OFF + ELF64_SYM_SIZE, (uint32_t)dynstr_import_off, 460 ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), SHN_UNDEF, 0, 0); 461 put_rela(b, RELA_OFF, got_va, ELF64_R_INFO(1u, ELF_R_RISCV_JUMP_SLOT), 0); 462 463 put_dyn(b, DYNAMIC_OFF + 0u * ELF64_DYN_SIZE, DT_NEEDED, dynstr_needed_off); 464 put_dyn(b, DYNAMIC_OFF + 1u * ELF64_DYN_SIZE, DT_STRTAB, dynstr_va); 465 put_dyn(b, DYNAMIC_OFF + 2u * ELF64_DYN_SIZE, DT_STRSZ, dynstr_len); 466 put_dyn(b, DYNAMIC_OFF + 3u * ELF64_DYN_SIZE, DT_SYMTAB, dynsym_va); 467 put_dyn(b, DYNAMIC_OFF + 4u * ELF64_DYN_SIZE, DT_SYMENT, ELF64_SYM_SIZE); 468 put_dyn(b, DYNAMIC_OFF + 5u * ELF64_DYN_SIZE, DT_PLTREL, DT_RELA); 469 put_dyn(b, DYNAMIC_OFF + 6u * ELF64_DYN_SIZE, DT_JMPREL, rela_va); 470 put_dyn(b, DYNAMIC_OFF + 7u * ELF64_DYN_SIZE, DT_PLTRELSZ, ELF64_RELA_SIZE); 471 put_dyn(b, DYNAMIC_OFF + 8u * ELF64_DYN_SIZE, DT_RELAENT, ELF64_RELA_SIZE); 472 put_dyn(b, DYNAMIC_OFF + 9u * ELF64_DYN_SIZE, DT_NULL, 0); 473 474 put64(b, TLS_OFF, 11u); 475 *out_len = TOTAL; 476 return b; 477 } 478 479 static unsigned char* build_tls_distinct_elf(size_t* out_len) { 480 enum { 481 PAGE = 0x1000u, 482 BASE_VA = 0x10000ull, 483 PHNUM = 3u, 484 TEXT_OFF = 0x1000u, 485 TLS_OFF = 0x2000u, 486 TOTAL = 0x2010u, 487 }; 488 const uint64_t text_va = BASE_VA + TEXT_OFF; 489 const uint64_t tls_va = BASE_VA + TLS_OFF; 490 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 491 if (!b) return NULL; 492 493 b[EI_MAG0] = ELFMAG0; 494 b[EI_MAG1] = ELFMAG1; 495 b[EI_MAG2] = ELFMAG2; 496 b[EI_MAG3] = ELFMAG3; 497 b[EI_CLASS] = ELFCLASS64; 498 b[EI_DATA] = ELFDATA2LSB; 499 b[EI_VERSION] = EV_CURRENT; 500 b[EI_OSABI] = ELFOSABI_LINUX; 501 put16(b, 16, ET_EXEC); 502 put16(b, 18, EM_RISCV); 503 put32(b, 20, EV_CURRENT); 504 put64(b, 24, text_va); 505 put64(b, 32, ELF64_EHDR_SIZE); 506 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 507 put16(b, 52, ELF64_EHDR_SIZE); 508 put16(b, 54, ELF64_PHDR_SIZE); 509 put16(b, 56, PHNUM); 510 511 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 512 TEXT_OFF + 40u, TEXT_OFF + 40u, PAGE); 513 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, TLS_OFF, tls_va, 514 16u, 16u, PAGE); 515 put_phdr(b, 64 + 2u * ELF64_PHDR_SIZE, PT_TLS, PF_R, TLS_OFF, tls_va, 8u, 16u, 516 8u); 517 518 put32(b, TEXT_OFF + 0u, rv_auipc(RV_T0, rv_pcrel_hi(text_va, tls_va))); 519 put32(b, TEXT_OFF + 4u, rv_addi(RV_T0, RV_T0, rv_pcrel_lo(text_va, tls_va))); 520 put32(b, TEXT_OFF + 8u, rv_addi(RV_T1, RV_ZERO, 9)); 521 put32(b, TEXT_OFF + 12u, rv_sd(RV_T1, RV_TP, 0)); 522 put32(b, TEXT_OFF + 16u, rv_ld(RV_A0, RV_T0, 0)); 523 put32(b, TEXT_OFF + 20u, rv_ld(RV_T2, RV_TP, 0)); 524 put32(b, TEXT_OFF + 24u, rv_add(RV_A0, RV_A0, RV_T2)); 525 put32(b, TEXT_OFF + 28u, rv_addi(RV_A7, RV_ZERO, 94)); 526 put32(b, TEXT_OFF + 32u, rv_ecall()); 527 528 put64(b, TLS_OFF, 11u); 529 *out_len = TOTAL; 530 return b; 531 } 532 533 static unsigned char* build_host_import_elf(size_t* out_len) { 534 enum { 535 PAGE = 0x1000u, 536 BASE_VA = 0x10000ull, 537 PHNUM = 3u, 538 TEXT_OFF = 0x1000u, 539 DYNSTR_OFF = 0x1100u, 540 DYNSYM_OFF = 0x1180u, 541 RELA_OFF = 0x1200u, 542 DYNAMIC_OFF = 0x2000u, 543 GOT_OFF = 0x2100u, 544 TOTAL = 0x2200u, 545 }; 546 const uint64_t text_va = BASE_VA + TEXT_OFF; 547 const uint64_t dynstr_va = BASE_VA + DYNSTR_OFF; 548 const uint64_t dynsym_va = BASE_VA + DYNSYM_OFF; 549 const uint64_t rela_va = BASE_VA + RELA_OFF; 550 const uint64_t dynamic_va = BASE_VA + DYNAMIC_OFF; 551 const uint64_t got_va = BASE_VA + GOT_OFF; 552 const char needed[] = "libhostbridge.so"; 553 const char import_name[] = "host_add2"; 554 const size_t dynstr_needed_off = 1u; 555 const size_t dynstr_import_off = 1u + sizeof(needed); 556 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 557 unsigned char* ds; 558 size_t dynstr_len; 559 if (!b) return NULL; 560 561 b[EI_MAG0] = ELFMAG0; 562 b[EI_MAG1] = ELFMAG1; 563 b[EI_MAG2] = ELFMAG2; 564 b[EI_MAG3] = ELFMAG3; 565 b[EI_CLASS] = ELFCLASS64; 566 b[EI_DATA] = ELFDATA2LSB; 567 b[EI_VERSION] = EV_CURRENT; 568 b[EI_OSABI] = ELFOSABI_LINUX; 569 put16(b, 16, ET_EXEC); 570 put16(b, 18, EM_RISCV); 571 put32(b, 20, EV_CURRENT); 572 put64(b, 24, text_va); 573 put64(b, 32, ELF64_EHDR_SIZE); 574 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 575 put16(b, 52, ELF64_EHDR_SIZE); 576 put16(b, 54, ELF64_PHDR_SIZE); 577 put16(b, 56, PHNUM); 578 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 579 0x1300u, 0x1300u, PAGE); 580 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DYNAMIC_OFF, 581 dynamic_va, GOT_OFF + 8u - DYNAMIC_OFF, GOT_OFF + 8u - DYNAMIC_OFF, 582 PAGE); 583 put_phdr(b, 64 + 2u * ELF64_PHDR_SIZE, PT_DYNAMIC, PF_R | PF_W, DYNAMIC_OFF, 584 dynamic_va, 10u * ELF64_DYN_SIZE, 10u * ELF64_DYN_SIZE, 8u); 585 586 put32(b, TEXT_OFF + 0u, rv_auipc(RV_T0, rv_pcrel_hi(text_va, got_va))); 587 put32(b, TEXT_OFF + 4u, rv_ld(RV_T0, RV_T0, rv_pcrel_lo(text_va, got_va))); 588 put32(b, TEXT_OFF + 8u, rv_addi(RV_A0, RV_ZERO, 35)); 589 put32(b, TEXT_OFF + 12u, rv_addi(RV_A1, RV_ZERO, 7)); 590 put32(b, TEXT_OFF + 16u, rv_jalr(RV_RA, RV_T0, 0)); 591 put32(b, TEXT_OFF + 20u, rv_addi(RV_A7, RV_ZERO, 94)); 592 put32(b, TEXT_OFF + 24u, rv_ecall()); 593 594 ds = b + DYNSTR_OFF; 595 ds[0] = 0; 596 memcpy(ds + dynstr_needed_off, needed, sizeof(needed)); 597 memcpy(ds + dynstr_import_off, import_name, sizeof(import_name)); 598 dynstr_len = dynstr_import_off + sizeof(import_name); 599 put_sym(b, DYNSYM_OFF, 0, 0, SHN_UNDEF, 0, 0); 600 put_sym(b, DYNSYM_OFF + ELF64_SYM_SIZE, (uint32_t)dynstr_import_off, 601 ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), SHN_UNDEF, 0, 0); 602 put_rela(b, RELA_OFF, got_va, ELF64_R_INFO(1u, ELF_R_RISCV_JUMP_SLOT), 0); 603 put_dyn(b, DYNAMIC_OFF + 0u * ELF64_DYN_SIZE, DT_NEEDED, dynstr_needed_off); 604 put_dyn(b, DYNAMIC_OFF + 1u * ELF64_DYN_SIZE, DT_STRTAB, dynstr_va); 605 put_dyn(b, DYNAMIC_OFF + 2u * ELF64_DYN_SIZE, DT_STRSZ, dynstr_len); 606 put_dyn(b, DYNAMIC_OFF + 3u * ELF64_DYN_SIZE, DT_SYMTAB, dynsym_va); 607 put_dyn(b, DYNAMIC_OFF + 4u * ELF64_DYN_SIZE, DT_SYMENT, ELF64_SYM_SIZE); 608 put_dyn(b, DYNAMIC_OFF + 5u * ELF64_DYN_SIZE, DT_PLTREL, DT_RELA); 609 put_dyn(b, DYNAMIC_OFF + 6u * ELF64_DYN_SIZE, DT_JMPREL, rela_va); 610 put_dyn(b, DYNAMIC_OFF + 7u * ELF64_DYN_SIZE, DT_PLTRELSZ, ELF64_RELA_SIZE); 611 put_dyn(b, DYNAMIC_OFF + 8u * ELF64_DYN_SIZE, DT_RELAENT, ELF64_RELA_SIZE); 612 put_dyn(b, DYNAMIC_OFF + 9u * ELF64_DYN_SIZE, DT_NULL, 0); 613 *out_len = TOTAL; 614 return b; 615 } 616 617 static unsigned char* build_dso_import_main_elf(size_t* out_len) { 618 enum { 619 PAGE = 0x1000u, 620 BASE_VA = 0x10000ull, 621 PHNUM = 3u, 622 TEXT_OFF = 0x1000u, 623 DYNSTR_OFF = 0x1100u, 624 DYNSYM_OFF = 0x1180u, 625 RELA_OFF = 0x1200u, 626 DYNAMIC_OFF = 0x2000u, 627 GOT_OFF = 0x2100u, 628 TOTAL = 0x2200u, 629 }; 630 const uint64_t text_va = BASE_VA + TEXT_OFF; 631 const uint64_t dynstr_va = BASE_VA + DYNSTR_OFF; 632 const uint64_t dynsym_va = BASE_VA + DYNSYM_OFF; 633 const uint64_t rela_va = BASE_VA + RELA_OFF; 634 const uint64_t dynamic_va = BASE_VA + DYNAMIC_OFF; 635 const uint64_t got_va = BASE_VA + GOT_OFF; 636 const char needed[] = "libdsoadd.so"; 637 const char import_name[] = "dso_add"; 638 const size_t dynstr_needed_off = 1u; 639 const size_t dynstr_import_off = 1u + sizeof(needed); 640 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 641 unsigned char* ds; 642 size_t dynstr_len; 643 if (!b) return NULL; 644 645 b[EI_MAG0] = ELFMAG0; 646 b[EI_MAG1] = ELFMAG1; 647 b[EI_MAG2] = ELFMAG2; 648 b[EI_MAG3] = ELFMAG3; 649 b[EI_CLASS] = ELFCLASS64; 650 b[EI_DATA] = ELFDATA2LSB; 651 b[EI_VERSION] = EV_CURRENT; 652 b[EI_OSABI] = ELFOSABI_LINUX; 653 put16(b, 16, ET_EXEC); 654 put16(b, 18, EM_RISCV); 655 put32(b, 20, EV_CURRENT); 656 put64(b, 24, text_va); 657 put64(b, 32, ELF64_EHDR_SIZE); 658 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 659 put16(b, 52, ELF64_EHDR_SIZE); 660 put16(b, 54, ELF64_PHDR_SIZE); 661 put16(b, 56, PHNUM); 662 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 663 0x1300u, 0x1300u, PAGE); 664 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DYNAMIC_OFF, 665 dynamic_va, GOT_OFF + 8u - DYNAMIC_OFF, GOT_OFF + 8u - DYNAMIC_OFF, 666 PAGE); 667 put_phdr(b, 64 + 2u * ELF64_PHDR_SIZE, PT_DYNAMIC, PF_R | PF_W, DYNAMIC_OFF, 668 dynamic_va, 10u * ELF64_DYN_SIZE, 10u * ELF64_DYN_SIZE, 8u); 669 670 put32(b, TEXT_OFF + 0u, rv_auipc(RV_T0, rv_pcrel_hi(text_va, got_va))); 671 put32(b, TEXT_OFF + 4u, rv_ld(RV_T0, RV_T0, rv_pcrel_lo(text_va, got_va))); 672 put32(b, TEXT_OFF + 8u, rv_addi(RV_A0, RV_ZERO, 35)); 673 put32(b, TEXT_OFF + 12u, rv_jalr(RV_RA, RV_T0, 0)); 674 put32(b, TEXT_OFF + 16u, rv_addi(RV_A7, RV_ZERO, 94)); 675 put32(b, TEXT_OFF + 20u, rv_ecall()); 676 677 ds = b + DYNSTR_OFF; 678 ds[0] = 0; 679 memcpy(ds + dynstr_needed_off, needed, sizeof(needed)); 680 memcpy(ds + dynstr_import_off, import_name, sizeof(import_name)); 681 dynstr_len = dynstr_import_off + sizeof(import_name); 682 put_sym(b, DYNSYM_OFF, 0, 0, SHN_UNDEF, 0, 0); 683 put_sym(b, DYNSYM_OFF + ELF64_SYM_SIZE, (uint32_t)dynstr_import_off, 684 ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), SHN_UNDEF, 0, 0); 685 put_rela(b, RELA_OFF, got_va, ELF64_R_INFO(1u, ELF_R_RISCV_JUMP_SLOT), 0); 686 put_dyn(b, DYNAMIC_OFF + 0u * ELF64_DYN_SIZE, DT_NEEDED, dynstr_needed_off); 687 put_dyn(b, DYNAMIC_OFF + 1u * ELF64_DYN_SIZE, DT_STRTAB, dynstr_va); 688 put_dyn(b, DYNAMIC_OFF + 2u * ELF64_DYN_SIZE, DT_STRSZ, dynstr_len); 689 put_dyn(b, DYNAMIC_OFF + 3u * ELF64_DYN_SIZE, DT_SYMTAB, dynsym_va); 690 put_dyn(b, DYNAMIC_OFF + 4u * ELF64_DYN_SIZE, DT_SYMENT, ELF64_SYM_SIZE); 691 put_dyn(b, DYNAMIC_OFF + 5u * ELF64_DYN_SIZE, DT_PLTREL, DT_RELA); 692 put_dyn(b, DYNAMIC_OFF + 6u * ELF64_DYN_SIZE, DT_JMPREL, rela_va); 693 put_dyn(b, DYNAMIC_OFF + 7u * ELF64_DYN_SIZE, DT_PLTRELSZ, ELF64_RELA_SIZE); 694 put_dyn(b, DYNAMIC_OFF + 8u * ELF64_DYN_SIZE, DT_RELAENT, ELF64_RELA_SIZE); 695 put_dyn(b, DYNAMIC_OFF + 9u * ELF64_DYN_SIZE, DT_NULL, 0); 696 *out_len = TOTAL; 697 return b; 698 } 699 700 static unsigned char* build_dso_import_so(size_t* out_len) { 701 enum { 702 PAGE = 0x1000u, 703 PHNUM = 3u, 704 TEXT_OFF = 0x1000u, 705 DYNAMIC_OFF = 0x2000u, 706 DYNSTR_OFF = 0x2100u, 707 DYNSYM_OFF = 0x2180u, 708 HASH_OFF = 0x2200u, 709 RELA_OFF = 0x2220u, 710 DATA_OFF = 0x2300u, 711 TOTAL = 0x2400u, 712 }; 713 const uint64_t text_va = TEXT_OFF; 714 const uint64_t dynamic_va = DYNAMIC_OFF; 715 const uint64_t dynstr_va = DYNSTR_OFF; 716 const uint64_t dynsym_va = DYNSYM_OFF; 717 const uint64_t hash_va = HASH_OFF; 718 const uint64_t rela_va = RELA_OFF; 719 const uint64_t ptr_va = DATA_OFF; 720 const uint64_t value_va = DATA_OFF + 8u; 721 const char soname[] = "libdsoadd.so"; 722 const char symbol[] = "dso_add"; 723 const size_t dynstr_soname_off = 1u; 724 const size_t dynstr_symbol_off = 1u + sizeof(soname); 725 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 726 unsigned char* ds; 727 size_t dynstr_len; 728 if (!b) return NULL; 729 730 b[EI_MAG0] = ELFMAG0; 731 b[EI_MAG1] = ELFMAG1; 732 b[EI_MAG2] = ELFMAG2; 733 b[EI_MAG3] = ELFMAG3; 734 b[EI_CLASS] = ELFCLASS64; 735 b[EI_DATA] = ELFDATA2LSB; 736 b[EI_VERSION] = EV_CURRENT; 737 b[EI_OSABI] = ELFOSABI_LINUX; 738 put16(b, 16, ET_DYN); 739 put16(b, 18, EM_RISCV); 740 put32(b, 20, EV_CURRENT); 741 put64(b, 24, text_va); 742 put64(b, 32, ELF64_EHDR_SIZE); 743 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 744 put16(b, 52, ELF64_EHDR_SIZE); 745 put16(b, 54, ELF64_PHDR_SIZE); 746 put16(b, 56, PHNUM); 747 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, 0, 748 TEXT_OFF + 24u, TEXT_OFF + 24u, PAGE); 749 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DYNAMIC_OFF, 750 dynamic_va, DATA_OFF + 16u - DYNAMIC_OFF, 751 DATA_OFF + 16u - DYNAMIC_OFF, PAGE); 752 put_phdr(b, 64 + 2u * ELF64_PHDR_SIZE, PT_DYNAMIC, PF_R | PF_W, DYNAMIC_OFF, 753 dynamic_va, 10u * ELF64_DYN_SIZE, 10u * ELF64_DYN_SIZE, 8u); 754 755 put32(b, TEXT_OFF + 0u, rv_auipc(RV_T0, rv_pcrel_hi(text_va, ptr_va))); 756 put32(b, TEXT_OFF + 4u, rv_ld(RV_T0, RV_T0, rv_pcrel_lo(text_va, ptr_va))); 757 put32(b, TEXT_OFF + 8u, rv_ld(RV_T1, RV_T0, 0)); 758 put32(b, TEXT_OFF + 12u, rv_add(RV_A0, RV_A0, RV_T1)); 759 put32(b, TEXT_OFF + 16u, rv_jalr(RV_ZERO, RV_RA, 0)); 760 761 ds = b + DYNSTR_OFF; 762 ds[0] = 0; 763 memcpy(ds + dynstr_soname_off, soname, sizeof(soname)); 764 memcpy(ds + dynstr_symbol_off, symbol, sizeof(symbol)); 765 dynstr_len = dynstr_symbol_off + sizeof(symbol); 766 put_sym(b, DYNSYM_OFF, 0, 0, SHN_UNDEF, 0, 0); 767 put_sym(b, DYNSYM_OFF + ELF64_SYM_SIZE, (uint32_t)dynstr_symbol_off, 768 ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), 1u, text_va, 20u); 769 put32(b, HASH_OFF + 0u, 1u); 770 put32(b, HASH_OFF + 4u, 2u); 771 put32(b, HASH_OFF + 8u, 1u); 772 put32(b, HASH_OFF + 12u, 0u); 773 put_rela(b, RELA_OFF, ptr_va, ELF64_R_INFO(0u, ELF_R_RISCV_RELATIVE), 774 (int64_t)value_va); 775 put64(b, DATA_OFF + 8u, 7u); 776 put_dyn(b, DYNAMIC_OFF + 0u * ELF64_DYN_SIZE, DT_SONAME, dynstr_soname_off); 777 put_dyn(b, DYNAMIC_OFF + 1u * ELF64_DYN_SIZE, DT_STRTAB, dynstr_va); 778 put_dyn(b, DYNAMIC_OFF + 2u * ELF64_DYN_SIZE, DT_STRSZ, dynstr_len); 779 put_dyn(b, DYNAMIC_OFF + 3u * ELF64_DYN_SIZE, DT_SYMTAB, dynsym_va); 780 put_dyn(b, DYNAMIC_OFF + 4u * ELF64_DYN_SIZE, DT_SYMENT, ELF64_SYM_SIZE); 781 put_dyn(b, DYNAMIC_OFF + 5u * ELF64_DYN_SIZE, DT_HASH, hash_va); 782 put_dyn(b, DYNAMIC_OFF + 6u * ELF64_DYN_SIZE, DT_RELA, rela_va); 783 put_dyn(b, DYNAMIC_OFF + 7u * ELF64_DYN_SIZE, DT_RELASZ, ELF64_RELA_SIZE); 784 put_dyn(b, DYNAMIC_OFF + 8u * ELF64_DYN_SIZE, DT_RELAENT, ELF64_RELA_SIZE); 785 put_dyn(b, DYNAMIC_OFF + 9u * ELF64_DYN_SIZE, DT_NULL, 0); 786 *out_len = TOTAL; 787 return b; 788 } 789 790 /* Static fixture for the intended permission/fault/signal surface. The guest 791 * installs a minimal SIGSEGV handler, writes to its RX text page, and expects 792 * Linux/RV64 signal delivery to transfer control to `handler`, which exits 42. 793 */ 794 static unsigned char* build_signal_perms_elf(size_t* out_len) { 795 enum { 796 PAGE = 0x1000u, 797 BASE_VA = 0x10000ull, 798 TEXT_OFF = 0x1000u, 799 DATA_OFF = 0x2000u, 800 TOTAL = 0x2040u, 801 }; 802 const uint64_t text_va = BASE_VA + TEXT_OFF; 803 const uint64_t data_va = BASE_VA + DATA_OFF; 804 const uint64_t handler_va = text_va + 48u; 805 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 806 807 if (!b) return NULL; 808 809 b[EI_MAG0] = ELFMAG0; 810 b[EI_MAG1] = ELFMAG1; 811 b[EI_MAG2] = ELFMAG2; 812 b[EI_MAG3] = ELFMAG3; 813 b[EI_CLASS] = ELFCLASS64; 814 b[EI_DATA] = ELFDATA2LSB; 815 b[EI_VERSION] = EV_CURRENT; 816 b[EI_OSABI] = ELFOSABI_LINUX; 817 put16(b, 16, ET_EXEC); 818 put16(b, 18, EM_RISCV); 819 put32(b, 20, EV_CURRENT); 820 put64(b, 24, text_va); 821 put64(b, 32, ELF64_EHDR_SIZE); 822 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 823 put16(b, 52, ELF64_EHDR_SIZE); 824 put16(b, 54, ELF64_PHDR_SIZE); 825 put16(b, 56, 2); 826 827 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 828 TEXT_OFF + 60u, TEXT_OFF + 60u, PAGE); 829 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DATA_OFF, 830 data_va, 32u, 32u, PAGE); 831 832 put32(b, TEXT_OFF + 0u, rv_addi(RV_A0, RV_ZERO, 11)); /* SIGSEGV */ 833 put32(b, TEXT_OFF + 4u, rv_auipc(RV_A1, rv_pcrel_hi(text_va + 4u, data_va))); 834 put32(b, TEXT_OFF + 8u, 835 rv_addi(RV_A1, RV_A1, rv_pcrel_lo(text_va + 4u, data_va))); 836 put32(b, TEXT_OFF + 12u, rv_addi(RV_A2, RV_ZERO, 0)); 837 put32(b, TEXT_OFF + 16u, rv_addi(RV_A3, RV_ZERO, 8)); 838 put32(b, TEXT_OFF + 20u, rv_addi(RV_A7, RV_ZERO, 134)); /* rt_sigaction */ 839 put32(b, TEXT_OFF + 24u, rv_ecall()); 840 put32(b, TEXT_OFF + 28u, rv_auipc(RV_T0, 0)); 841 put32(b, TEXT_OFF + 32u, rv_sd(RV_ZERO, RV_T0, 0)); 842 put32(b, TEXT_OFF + 36u, rv_addi(RV_A0, RV_ZERO, 1)); 843 put32(b, TEXT_OFF + 40u, rv_addi(RV_A7, RV_ZERO, 94)); 844 put32(b, TEXT_OFF + 44u, rv_ecall()); 845 put32(b, TEXT_OFF + 48u, rv_addi(RV_A0, RV_ZERO, 42)); 846 put32(b, TEXT_OFF + 52u, rv_addi(RV_A7, RV_ZERO, 94)); 847 put32(b, TEXT_OFF + 56u, rv_ecall()); 848 849 put64(b, DATA_OFF + 0u, handler_va); 850 put64(b, DATA_OFF + 8u, 0); 851 put64(b, DATA_OFF + 16u, 0); 852 put64(b, DATA_OFF + 24u, 0); 853 854 *out_len = TOTAL; 855 return b; 856 } 857 858 static unsigned char* build_signal_load_fault_elf(size_t* out_len) { 859 enum { 860 PAGE = 0x1000u, 861 BASE_VA = 0x10000ull, 862 TEXT_OFF = 0x1000u, 863 DATA_OFF = 0x2000u, 864 TOTAL = 0x2040u, 865 }; 866 const uint64_t text_va = BASE_VA + TEXT_OFF; 867 const uint64_t data_va = BASE_VA + DATA_OFF; 868 const uint64_t handler_va = text_va + 48u; 869 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 870 871 if (!b) return NULL; 872 873 b[EI_MAG0] = ELFMAG0; 874 b[EI_MAG1] = ELFMAG1; 875 b[EI_MAG2] = ELFMAG2; 876 b[EI_MAG3] = ELFMAG3; 877 b[EI_CLASS] = ELFCLASS64; 878 b[EI_DATA] = ELFDATA2LSB; 879 b[EI_VERSION] = EV_CURRENT; 880 b[EI_OSABI] = ELFOSABI_LINUX; 881 put16(b, 16, ET_EXEC); 882 put16(b, 18, EM_RISCV); 883 put32(b, 20, EV_CURRENT); 884 put64(b, 24, text_va); 885 put64(b, 32, ELF64_EHDR_SIZE); 886 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 887 put16(b, 52, ELF64_EHDR_SIZE); 888 put16(b, 54, ELF64_PHDR_SIZE); 889 put16(b, 56, 2); 890 891 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 892 TEXT_OFF + 60u, TEXT_OFF + 60u, PAGE); 893 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DATA_OFF, 894 data_va, 32u, 32u, PAGE); 895 896 put32(b, TEXT_OFF + 0u, rv_addi(RV_A0, RV_ZERO, 11)); 897 put32(b, TEXT_OFF + 4u, rv_auipc(RV_A1, rv_pcrel_hi(text_va + 4u, data_va))); 898 put32(b, TEXT_OFF + 8u, 899 rv_addi(RV_A1, RV_A1, rv_pcrel_lo(text_va + 4u, data_va))); 900 put32(b, TEXT_OFF + 12u, rv_addi(RV_A2, RV_ZERO, 0)); 901 put32(b, TEXT_OFF + 16u, rv_addi(RV_A3, RV_ZERO, 8)); 902 put32(b, TEXT_OFF + 20u, rv_addi(RV_A7, RV_ZERO, 134)); 903 put32(b, TEXT_OFF + 24u, rv_ecall()); 904 put32(b, TEXT_OFF + 28u, rv_addi(RV_T0, RV_ZERO, 0)); 905 put32(b, TEXT_OFF + 32u, rv_ld(RV_T1, RV_T0, 0)); 906 put32(b, TEXT_OFF + 36u, rv_addi(RV_A0, RV_ZERO, 1)); 907 put32(b, TEXT_OFF + 40u, rv_addi(RV_A7, RV_ZERO, 94)); 908 put32(b, TEXT_OFF + 44u, rv_ecall()); 909 put32(b, TEXT_OFF + 48u, rv_addi(RV_A0, RV_ZERO, 42)); 910 put32(b, TEXT_OFF + 52u, rv_addi(RV_A7, RV_ZERO, 94)); 911 put32(b, TEXT_OFF + 56u, rv_ecall()); 912 913 put64(b, DATA_OFF + 0u, handler_va); 914 put64(b, DATA_OFF + 8u, 0); 915 put64(b, DATA_OFF + 16u, 0); 916 put64(b, DATA_OFF + 24u, 0); 917 918 *out_len = TOTAL; 919 return b; 920 } 921 922 static unsigned char* build_signal_sigreturn_elf(size_t* out_len) { 923 enum { 924 PAGE = 0x1000u, 925 BASE_VA = 0x10000ull, 926 TEXT_OFF = 0x1000u, 927 DATA_OFF = 0x2000u, 928 TOTAL = 0x2040u, 929 }; 930 const uint64_t text_va = BASE_VA + TEXT_OFF; 931 const uint64_t data_va = BASE_VA + DATA_OFF; 932 const uint64_t handler_va = text_va + 48u; 933 unsigned char* b = (unsigned char*)calloc(1, TOTAL); 934 if (!b) return NULL; 935 936 b[EI_MAG0] = ELFMAG0; 937 b[EI_MAG1] = ELFMAG1; 938 b[EI_MAG2] = ELFMAG2; 939 b[EI_MAG3] = ELFMAG3; 940 b[EI_CLASS] = ELFCLASS64; 941 b[EI_DATA] = ELFDATA2LSB; 942 b[EI_VERSION] = EV_CURRENT; 943 b[EI_OSABI] = ELFOSABI_LINUX; 944 put16(b, 16, ET_EXEC); 945 put16(b, 18, EM_RISCV); 946 put32(b, 20, EV_CURRENT); 947 put64(b, 24, text_va); 948 put64(b, 32, ELF64_EHDR_SIZE); 949 put32(b, 48, EF_RISCV_FLOAT_ABI_DOUBLE); 950 put16(b, 52, ELF64_EHDR_SIZE); 951 put16(b, 54, ELF64_PHDR_SIZE); 952 put16(b, 56, 2); 953 954 put_phdr(b, 64 + 0u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_X, 0, BASE_VA, 955 TEXT_OFF + 80u, TEXT_OFF + 80u, PAGE); 956 put_phdr(b, 64 + 1u * ELF64_PHDR_SIZE, PT_LOAD, PF_R | PF_W, DATA_OFF, 957 data_va, 32u, 32u, PAGE); 958 959 put32(b, TEXT_OFF + 0u, rv_addi(RV_A0, RV_ZERO, 11)); 960 put32(b, TEXT_OFF + 4u, rv_auipc(RV_A1, rv_pcrel_hi(text_va + 4u, data_va))); 961 put32(b, TEXT_OFF + 8u, 962 rv_addi(RV_A1, RV_A1, rv_pcrel_lo(text_va + 4u, data_va))); 963 put32(b, TEXT_OFF + 12u, rv_addi(RV_A2, RV_ZERO, 0)); 964 put32(b, TEXT_OFF + 16u, rv_addi(RV_A3, RV_ZERO, 8)); 965 put32(b, TEXT_OFF + 20u, rv_addi(RV_A7, RV_ZERO, 134)); 966 put32(b, TEXT_OFF + 24u, rv_ecall()); 967 put32(b, TEXT_OFF + 28u, rv_auipc(RV_T0, 0)); 968 put32(b, TEXT_OFF + 32u, rv_sd(RV_ZERO, RV_T0, 0)); 969 put32(b, TEXT_OFF + 36u, rv_addi(RV_A0, RV_ZERO, 42)); 970 put32(b, TEXT_OFF + 40u, rv_addi(RV_A7, RV_ZERO, 94)); 971 put32(b, TEXT_OFF + 44u, rv_ecall()); 972 973 put32(b, TEXT_OFF + 48u, rv_auipc(RV_A0, rv_pcrel_hi(handler_va, text_va))); 974 put32(b, TEXT_OFF + 52u, 975 rv_addi(RV_A0, RV_A0, rv_pcrel_lo(handler_va, text_va))); 976 put32(b, TEXT_OFF + 56u, rv_addi(RV_A1, RV_ZERO, 1)); 977 put32(b, TEXT_OFF + 60u, rv_addi(RV_A2, RV_ZERO, 7)); 978 put32(b, TEXT_OFF + 64u, rv_addi(RV_A7, RV_ZERO, 226)); 979 put32(b, TEXT_OFF + 68u, rv_ecall()); 980 put32(b, TEXT_OFF + 72u, rv_addi(RV_A7, RV_ZERO, 139)); 981 put32(b, TEXT_OFF + 76u, rv_ecall()); 982 983 put64(b, DATA_OFF + 0u, handler_va); 984 put64(b, DATA_OFF + 8u, 0); 985 put64(b, DATA_OFF + 16u, 0); 986 put64(b, DATA_OFF + 24u, 0); 987 *out_len = TOTAL; 988 return b; 989 } 990 991 /* ============================================================ 992 * Decoder smoke (sanity-check a handful of encodings before the 993 * end-to-end JIT run). 994 * ============================================================ */ 995 static void emu_fixture_expect_exit_with_bindings( 996 const char* name, unsigned char* elf, size_t elf_len, int want_exit, 997 uint32_t max_blocks, const KitEmuExternalBindings* bindings); 998 999 static void emu_fixture_expect_exit(const char* name, unsigned char* elf, 1000 size_t elf_len, int want_exit, 1001 uint32_t max_blocks) { 1002 KitEmuExternalBindings no_bindings; 1003 memset(&no_bindings, 0, sizeof(no_bindings)); 1004 emu_fixture_expect_exit_with_bindings(name, elf, elf_len, want_exit, 1005 max_blocks, &no_bindings); 1006 } 1007 1008 static void emu_fixture_expect_exit_with_bindings( 1009 const char* name, unsigned char* elf, size_t elf_len, int want_exit, 1010 uint32_t max_blocks, const KitEmuExternalBindings* bindings) { 1011 KitCompiler* c; 1012 KitJitHost host; 1013 KitEmuOptions opts; 1014 KitTargetSpec guest_target; 1015 KitStatus st; 1016 int exit_code = -1; 1017 long ps; 1018 (void)max_blocks; /* kit_emu_run drives the guest to its exit syscall */ 1019 1020 c = new_host_compiler(); 1021 if (!c) { 1022 free(elf); 1023 return; 1024 } 1025 ps = sysconf(_SC_PAGESIZE); 1026 if (ps > 0) g_execmem.page_size = (size_t)ps; 1027 1028 memset(&host, 0, sizeof(host)); 1029 host.execmem = &g_execmem; 1030 memset(&guest_target, 0, sizeof(guest_target)); 1031 guest_target.arch = KIT_ARCH_RV64; 1032 guest_target.os = KIT_OS_LINUX; 1033 guest_target.obj = KIT_OBJ_ELF; 1034 guest_target.ptr_size = 8u; 1035 guest_target.ptr_align = 8u; 1036 memset(&opts, 0, sizeof(opts)); 1037 opts.guest_bytes.data = elf; 1038 opts.guest_bytes.len = elf_len; 1039 opts.guest_target = guest_target; 1040 opts.has_guest_target = true; 1041 opts.jit_host = &host; 1042 if (bindings) opts.bindings = *bindings; 1043 1044 /* Public end-to-end entry: loads the guest, runs it to its exit syscall, and 1045 * returns the code. A guest fault makes kit_emu_run return non-OK. */ 1046 st = kit_emu_run(c, &opts, &exit_code); 1047 EXPECT(st == KIT_OK, "%s: kit_emu_run returned %d", name, (int)st); 1048 EXPECT(exit_code == want_exit, "%s: exit_code should be %d, got %d", name, 1049 want_exit, exit_code); 1050 if (st == KIT_OK && exit_code == want_exit) 1051 fprintf(stderr, "PASS %s\n", name); 1052 1053 free(elf); 1054 kit_compiler_free(c); 1055 } 1056 1057 static void jit_vertical_smoke(void) { 1058 unsigned char* elf; 1059 size_t elf_len; 1060 1061 elf = build_minimal_elf(&elf_len); 1062 EXPECT(elf != NULL, "static ELF buffer allocation failed"); 1063 if (!elf) return; 1064 emu_fixture_expect_exit("static-rv64-exit", elf, elf_len, 42, 8); 1065 } 1066 1067 static uint64_t host_plus5(uint64_t v) { return v + 5u; } 1068 static uint64_t host_add2(uint64_t a, uint64_t b) { return a + b; } 1069 1070 static KitStatus host_import_resolver(void* user, KitEmu* emu, 1071 const KitEmuImportRequest* req, 1072 KitEmuResolvedImport* out) { 1073 (void)user; 1074 (void)emu; 1075 memset(out, 0, sizeof(*out)); 1076 if (req && kit_slice_eq_cstr(req->symbol_name, "host_add2")) { 1077 out->host_fn = (void*)host_add2; 1078 out->signature.abi = KIT_EMU_IMPORT_ABI_GUEST_C; 1079 out->signature.result = KIT_EMU_VALUE_U64; 1080 out->signature.nargs = 2u; 1081 out->signature.args[0] = KIT_EMU_VALUE_U64; 1082 out->signature.args[1] = KIT_EMU_VALUE_U64; 1083 return KIT_OK; 1084 } 1085 if (req && kit_slice_eq_cstr(req->symbol_name, "import_add")) { 1086 out->host_fn = (void*)host_plus5; 1087 out->signature.abi = KIT_EMU_IMPORT_ABI_GUEST_C; 1088 out->signature.result = KIT_EMU_VALUE_U64; 1089 out->signature.nargs = 1u; 1090 out->signature.args[0] = KIT_EMU_VALUE_U64; 1091 return KIT_OK; 1092 } 1093 return KIT_NOT_FOUND; 1094 } 1095 1096 typedef struct DsoFixture { 1097 unsigned char* bytes; 1098 size_t len; 1099 } DsoFixture; 1100 1101 static KitStatus dso_object_resolver(void* user, KitEmu* emu, 1102 const KitEmuObjectRequest* req, 1103 KitEmuResolvedObject* out) { 1104 DsoFixture* d = (DsoFixture*)user; 1105 (void)emu; 1106 memset(out, 0, sizeof(*out)); 1107 if (d && req && kit_slice_eq_cstr(req->object_name, "libdsoadd.so")) { 1108 out->object_bytes.data = d->bytes; 1109 out->object_bytes.len = d->len; 1110 return KIT_OK; 1111 } 1112 return KIT_NOT_FOUND; 1113 } 1114 1115 static void dynamic_import_tls_red(void) { 1116 unsigned char* elf; 1117 size_t elf_len; 1118 1119 elf = build_dynamic_import_tls_elf(&elf_len); 1120 EXPECT(elf != NULL, "dynamic import/TLS ELF buffer allocation failed"); 1121 if (!elf) return; 1122 emu_fixture_expect_exit("dynamic-import-tls-rv64", elf, elf_len, 42, 32); 1123 } 1124 1125 static void host_import_bridge_smoke(void) { 1126 unsigned char* elf; 1127 size_t elf_len; 1128 KitEmuExternalBindings bindings; 1129 elf = build_host_import_elf(&elf_len); 1130 EXPECT(elf != NULL, "host import ELF buffer allocation failed"); 1131 if (!elf) return; 1132 memset(&bindings, 0, sizeof(bindings)); 1133 bindings.resolve_import = host_import_resolver; 1134 emu_fixture_expect_exit_with_bindings("host-import-bridge-rv64", elf, elf_len, 1135 42, 32, &bindings); 1136 } 1137 1138 static void dso_import_reloc_smoke(void) { 1139 unsigned char* elf; 1140 size_t elf_len; 1141 DsoFixture dso; 1142 KitEmuExternalBindings bindings; 1143 memset(&dso, 0, sizeof(dso)); 1144 dso.bytes = build_dso_import_so(&dso.len); 1145 EXPECT(dso.bytes != NULL, "DSO ELF buffer allocation failed"); 1146 if (!dso.bytes) return; 1147 elf = build_dso_import_main_elf(&elf_len); 1148 EXPECT(elf != NULL, "DSO main ELF buffer allocation failed"); 1149 if (!elf) { 1150 free(dso.bytes); 1151 return; 1152 } 1153 memset(&bindings, 0, sizeof(bindings)); 1154 bindings.resolve_object = dso_object_resolver; 1155 bindings.user = &dso; 1156 emu_fixture_expect_exit_with_bindings("dso-import-reloc-rv64", elf, elf_len, 1157 42, 64, &bindings); 1158 free(dso.bytes); 1159 } 1160 1161 static void tls_distinct_smoke(void) { 1162 unsigned char* elf; 1163 size_t elf_len; 1164 elf = build_tls_distinct_elf(&elf_len); 1165 EXPECT(elf != NULL, "distinct TLS ELF buffer allocation failed"); 1166 if (!elf) return; 1167 emu_fixture_expect_exit("tls-distinct-rv64", elf, elf_len, 20, 32); 1168 } 1169 1170 static void signal_perms_red(void) { 1171 unsigned char* elf; 1172 size_t elf_len; 1173 1174 elf = build_signal_perms_elf(&elf_len); 1175 EXPECT(elf != NULL, "signal/perms ELF buffer allocation failed"); 1176 if (!elf) return; 1177 emu_fixture_expect_exit("signal-perms-rv64", elf, elf_len, 42, 64); 1178 } 1179 1180 static void signal_load_fault_smoke(void) { 1181 unsigned char* elf; 1182 size_t elf_len; 1183 1184 elf = build_signal_load_fault_elf(&elf_len); 1185 EXPECT(elf != NULL, "signal/load-fault ELF buffer allocation failed"); 1186 if (!elf) return; 1187 emu_fixture_expect_exit("signal-load-fault-rv64", elf, elf_len, 42, 64); 1188 } 1189 1190 static void signal_sigreturn_smoke(void) { 1191 unsigned char* elf; 1192 size_t elf_len; 1193 elf = build_signal_sigreturn_elf(&elf_len); 1194 EXPECT(elf != NULL, "signal sigreturn ELF buffer allocation failed"); 1195 if (!elf) return; 1196 emu_fixture_expect_exit("signal-sigreturn-rv64", elf, elf_len, 42, 96); 1197 } 1198 1199 int main(void) { 1200 kit_unit_init(&g_u); 1201 jit_vertical_smoke(); 1202 dynamic_import_tls_red(); 1203 host_import_bridge_smoke(); 1204 dso_import_reloc_smoke(); 1205 tls_distinct_smoke(); 1206 signal_perms_red(); 1207 signal_load_fault_smoke(); 1208 signal_sigreturn_smoke(); 1209 if (g_u.fails) { 1210 fprintf(stderr, "FAILED %d check(s)\n", g_u.fails); 1211 return 1; 1212 } 1213 fprintf(stderr, "OK\n"); 1214 return 0; 1215 }