Belajar Assembly - Interop: Linking C & Libraries (glibc)
Episode 19 of 23

Belajar Assembly - Interop: Linking C & Libraries (glibc)

Menyatukan assembly dengan ekosistem C: linking lewat gcc, memanggil printf dan fungsi glibc dari assembly dengan aturan alignment 16-byte, memahami symbol resolution, GOT/PLT, dan position-independent code, serta membangun shared library .so dari kode assembly.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Sejauh ini program assembly kita berjalan tanpa libc — murni syscall. Episode 19 membalik arah: assembly memanggil libc, dan C memanggil assembly, dalam satu binary yang di-link oleh gcc. Inilah bentuk interop yang paling umum di dunia nyata: kode assembly untuk hot path, C/libc untuk segala yang lain.

Mengapa penting? Karena menulis semua string formatting, file I/O, dan networking dengan syscall mentah (seperti episode 10) adalah kerja sia-sia. Dan memahami GOT/PLT — mekanisme di balik pemanggilan fungsi dari shared library — adalah jembatan menuju topik kernel di episode 21 dan analisis binary di episode 16.

Memanggil printf dari Assembly

Perbedaan kunci dengan program syscall murni: program ini di-link dengan libc, dan _start-nya bukan lagi milik kita (libc menyediakan _start yang memanggil main). Ubah nama entry point:

print_printf.asm (NASM)
section .data
    fmt db "Nilai: %d", 0x0a, 0
 
section .text
    global main
    extern printf
 
main:
    push rbp
    mov rbp, rsp
 
    mov rsi, 42          ; argumen ke-2 printf: nilai integer
    lea rdi, [rel fmt]   ; argumen ke-1 printf: format string
    call printf
 
    pop rbp
    mov eax, 0           ; return 0 (int main)
    ret
Link dengan libc
nasm -f elf64 print_printf.asm -o print_printf.o
gcc -no-pie print_printf.o -o app
./app

Output: Nilai: 42.

Important

Aturan alignment 16-byte (episode 9) wajib dipatuhi. Saat main masuk, rsp % 16 == 8. Prologue push rbp membuat rsp % 16 == 0 — persis kondisi yang diharapkan sebelum call printf. Jika kalian melewati prologue (fungsi leaf tanpa push), RSP tetap 8 mod 16 saat call → glibc crash SIGSEGV. Ini bug paling umum pada kode assembly yang memanggil libc.

Mengapa lea rdi, [rel fmt]?

Di episode 3 kita menulis mov rsi, msg (alamat absolut). Dengan gcc -no-pie itu bekerja. Tetapi distro modern default memakai PIE (episode 17), di mana alamat binary di-randomisasi. Untuk kode position-independent, ambil alamat relatif terhadap RIP:

Position-independent
lea rdi, [rel fmt]     ; relatif ke RIP → aman untuk PIE

Dan link tanpa -no-pie:

Link PIE (default distro modern)
gcc print_printf.o -o app
./app

Ini menandai kode assembly kalian siap untuk binary modern yang ber-ASLR penuh.

GOT dan PLT: Mesin di Balik call printf

Saat call printf dieksekusi, ke mana tepatnya ia melompat? Karena printf tinggal di libc (shared library yang dimuat di alamat acak), alamatnya belum diketahui saat link. Mekanisme penyelesaiannya berlapis:

  1. PLT (Procedure Linkage Table) — tabel stub di binary: setiap entri berisi jmp ke GOT.
  2. GOT (Global Offset Table) — tabel alamat yang diisi linker saat runtime.
  3. Panggilan pertama: GOT berisi alamat resolver di linker; setelah resolved, GOT di-update ke alamat printf yang sebenarnya.
100%

Untuk kalian yang bekerja dengan assembly, yang perlu dipahami: call printf melalui PLT/GOT adalah indirection — biaya kecil demi shared library yang fleksibel. objdump -d akan menampilkan call 0x401030 <printf@plt> — alamat PLT, bukan libc.

Memanggil Fungsi Assembly dari C

Kita sudah melihat satu arah (episode 9). Mari lengkapi dengan pembuatan shared library — bentuk interop paling reusable:

mylib.asm (NASM)
section .text
    global square
 
; long square(long x)
square:
    mov rax, rdi
    imul rax, rax
    ret
Cmain.c
#include <stdio.h>
 
extern long square(long x);
 
int main(void) {
    printf("%ld\n", square(9));
    return 0;
}
Build dan jalankan
nasm -f elf64 mylib.asm -o mylib.o
gcc -shared -o libmylib.so mylib.o
gcc main.c -L. -lmylib -o app
LD_LIBRARY_PATH=. ./app

Output: 81. Perhatikan -shared menghasilkan .so, dan -lmylib menghubungkan -L. (direktori ini) ke libmylib.so.

Relocations dan Position-Independent Code

Saat membuat .so, kode di dalamnya harus position-independent karena akan dimuat di alamat acak:

Periksa relokasi
readelf -r libmylib.so
objdump -d libmylib.so | grep -A3 square

Konsekuensi praktis untuk penulis assembly:

  • Gunakan lea rdi, [rel symbol] untuk mengakses data/string.
  • Hindari alamat absolut; gunakan GOT jika perlu simbol eksternal (akses data global libc biasanya lewat GOT).
  • NASM mendukung ini dengan kombinasi rel dan, bila perlu, wrt ..got:
Akses data eksternal via GOT
extern some_global
mov rax, [rel some_global wrt ..got]

Tip

Trik debugging: jalankan readelf -d libmylib.so → perhatikan TEXTREL (teks yang mengandung relokasi — tandanya kode tidak benar-benar PIC) dan NEEDED (dependensi). Binary modern yang sehat seharusnya tanpa TEXTREL, karena mencegah berbagi halaman kode antar proses.

Kapan Menggunakan Mana

SituasiPilihan
Hot path numerik di aplikasi CFungsi assembly dipanggil C, di-link statis
Library yang dipakai banyak programShared library .so dari assembly
Program yang butuh bootstrap sebelum libc (bootloader, kernel)Murni syscall, tanpa libc (episode 3/10/21)
Mengambil alih rutin perf-kritis libcOverride simbol (LD_PRELOAD)

Common Pitfalls

  • RSP salah align sebelum call libc — crash SIGSEGV; jaga aturan 16-byte.
  • Alamat absolut di kode PIE — gunakan lea ... [rel ...].
  • Lupa extern di NASM — linker error unresolved symbol.
  • Nama main vs _start — dengan libc gunakan main; _start dipakai hanya tanpa libc.
  • Cara ganda exit — jangan syscall exit dalam program yang memakai libc; biarkan main ret (libc yang memanggil exit, memastikan flush buffer stdio).

Penutup

Pada episode 19 ini, kalian telah menyatukan assembly dengan ekosistem C.

Inti yang harus dibawa pulang:

  • Entry point main + link gcc untuk memakai libc; jaga alignment 16-byte sebelum call.
  • lea ... [rel ...] untuk alamat yang aman di kode PIE.
  • GOT/PLT adalah indirection yang menyelesaikan alamat shared library saat runtime.
  • Shared library .so dari assembly: gcc -shared; gunakan rel untuk PIC.
  • Pilih interop sesuai kebutuhan: hot path, library, atau murni syscall.

Di episode 20 selanjutnya, kalian diperbarui ke toolchain terbaru: NASM 3.02 (rilis 29 Juni 2026) dengan dukungan instruksi modern APX/AVX10 eksperimental, assembler terintegrasi LLVM/Clang dan llvm-objdump, serta Godbolt (Compiler Explorer) untuk melihat langsung bagaimana compiler menghasilkan assembly. Saatnya memakai semua skill membaca assembly kalian untuk "membaca pikiran" compiler.

Belajar Assembly - Interop: Linking C & Libraries (glibc) | Belajar Assembly