consumer.c (1983B)
1 /* test/link/elf-dso-aa64/consumer.c — DSO consumer; freestanding aarch64. 2 * 3 * Dynamically linked against libfoo.so. Provides bar_external so that 4 * libfoo.so's undefined import is satisfied at runtime via the executable's 5 * exported symbol table (requires --export-dynamic / -rdynamic at link time). 6 * 7 * Uses a direct SVC for exit so the binary needs no libc and no sysroot at 8 * compile time; only the dynamic linker and libfoo.so are needed at runtime. 9 * 10 * Exit codes: 11 * 0 all checks passed 12 * 1 foo_add(10, 32) != 42 (function export via PLT) 13 * 2 foo_get_counter() != 42 (function export via PLT, reads data internally) 14 * 3 foo_counter (direct read) != 42 (data export via GOT/GLOB_DAT) 15 */ 16 17 extern int foo_add(int a, int b); 18 extern int foo_get_counter(void); 19 /* Direct access to the exported data symbol. clang on aarch64 defaults to PIC 20 * so the compiler reads foo_counter through the GOT; the linker emits 21 * R_AARCH64_GLOB_DAT so the loader fills the GOT slot with the symbol's 22 * runtime address at startup. */ 23 extern int foo_counter; 24 25 /* Satisfies libfoo.so's undefined import of bar_external. Exported to the 26 * runtime dynamic symbol table by --export-dynamic on the consumer link. */ 27 int bar_external(int x) { (void)x; return 0; } 28 29 static __attribute__((noreturn)) void do_exit(int code) 30 { 31 /* aarch64 Linux: x8 = NR_exit_group (94), x0 = exit code */ 32 register long x8 __asm__("x8") = 94; 33 register long x0 __asm__("x0") = (long)code; 34 __asm__ volatile("svc 0" : : "r"(x8), "r"(x0) : "memory"); 35 __builtin_unreachable(); 36 } 37 38 void _start(void) 39 { 40 /* Function export: foo_add(10, 32) = 10 + 32 + bar_external(0) = 42 */ 41 if (foo_add(10, 32) != 42) do_exit(1); 42 /* Function export: foo_get_counter() returns foo_counter (42) */ 43 if (foo_get_counter() != 42) do_exit(2); 44 /* Data export: direct read through COPY reloc placed by the linker */ 45 if (foo_counter != 42) do_exit(3); 46 do_exit(0); 47 }