Geliştirici Araçları
TEKNİK REHBER GELİŞTİRİCİ ARAÇLARI BİNUTILS 2026

objdump —
ELF disassembler.

GNU binutils'in en güçlü aracı: ELF ikili dosyayı section'lara ayır, assembly çıktısı al, sembol tablolarını ve relocation'ları incele. ARM Thumb'dan x86-64'e her mimaride çalışır.

00 objdump nedir — ELF anatomy

objdump, GNU binutils paketinin bir parçasıdır ve ELF (Executable and Linkable Format) ikili dosyalarını çok çeşitli formatlarda incelemenizi sağlar. Embedded geliştirmede vazgeçilmezdir.

Bir ELF dosyası üç ana katmandan oluşur: ELF header (dosya tipi, hedef mimari, entry point), section header tablosu (linker'ın kullandığı bölümler: .text, .data, .bss...) ve program header tablosu (loader'ın kullandığı segment tanımları). objdump bu katmanları ayrı ayrı ya da hep birlikte gösterebilir.

Kurulum

bash
# Debian/Ubuntu — native (x86)
sudo apt install binutils

# ARM cross-toolchain ile birlikte gelir:
sudo apt install gcc-arm-linux-gnueabihf binutils-arm-linux-gnueabihf

# Kurulumu doğrula
arm-linux-gnueabihf-objdump --version
# GNU objdump (GNU Binutils for Debian) 2.38

# Yocto/Buildroot: SDK içinde aarch64-poky-linux-objdump vb.
which aarch64-poky-linux-objdump

Temel sözdizimi

bash
objdump [SEÇENEKLER] dosya

# Cross-compile edilmiş ARM ELF için hedef mimariye uygun araç kullan:
arm-linux-gnueabihf-objdump -d myprogram
İPUCU — doğru araç

Native objdump, ARM ELF dosyalarını da okuyabilir; ancak arm-linux-gnueabihf-objdump gibi hedef mimariye özgü araçlar daha doğru disassemble çıktısı üretir. Özellikle Thumb/Thumb-2 geçişlerinde bunu göreceksiniz.

01 -d — disassemble (ARM Thumb & x86-64)

-d bayrağı, çalıştırılabilir kod içeren tüm section'ları (genellikle .text) disassemble eder. ARM Thumb ve x86-64 çıktıları birbirinden oldukça farklıdır.

bash
# Temel disassemble
objdump -d /bin/ls | head -40

# ARM cross: Thumb-2 kodu
arm-linux-gnueabihf-objdump -d hello_arm

# Belirli bir fonksiyonu filtrele (grep ile)
objdump -d myapp | grep -A 30 '<main>:'

# Intel syntax (x86) — AT&T yerine Intel sözdizimi
objdump -d -M intel /bin/ls | head -20

x86-64 örnek çıktı

objdump -d çıktısı (x86-64)
0000000000001149 <main>:
    1149:       f3 0f 1e fa             endbr64
    114d:       55                      push   %rbp
    114e:       48 89 e5                mov    %rsp,%rbp
    1151:       48 83 ec 10             sub    $0x10,%rsp
    1155:       89 7d fc                mov    %edi,-0x4(%rbp)
    1158:       48 89 75 f0             mov    %rsi,-0x10(%rbp)
    115c:       bf 00 00 00 00          mov    $0x0,%edi
    1161:       e8 ea fe ff ff          call   1050 <puts@plt>
    1166:       b8 00 00 00 00          mov    $0x0,%eax
    116b:       c9                      leave
    116c:       c3                      ret

ARM Thumb-2 örnek çıktı

arm-linux-gnueabihf-objdump -d çıktısı
00010454 <main>:
   10454:       b580            push    {r7, lr}
   10456:       af00            add     r7, sp, #0
   10458:       f7ff effe       blx     10458 <puts@plt>
   1045c:       4603            mov     r3, r0
   1045e:       4618            mov     r0, r3
   10460:       bd80            pop     {r7, pc}

# Thumb talimatları 2 veya 4 bayttır (Thumb-2 karışık genişlik)
# 'blx' = Branch with Link and Exchange — Thumb/ARM modunu değiştirir

Tüm section'ları disassemble et

bash
# -D: tüm section'lar (data section'ları da dahil)
objdump -D firmware.elf | less

# Belirli bir section:
objdump -d --section=.text.startup myapp

02 -h — section headers

Section header tablosu, ELF dosyasındaki her bölümün adını, tipini, boyutunu ve bellek adresini listeler. Linker script sorunlarını debug etmek için temel araçtır.

bash
objdump -h myapp
çıktı
myapp:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00003a4c  00010000  00010000  00010000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       000004f8  00013a4c  00013a4c  00013a4c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00000124  00020000  00013f44  00013f44  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .bss          000008a0  00020124  00014068  00014068  2**3
                  ALLOC
  4 .debug_info   00012345  00000000  00000000  00014068  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS

Flag anlamları

ALLOC
Çalışma zamanında bellek tahsis edilir.
LOAD
Dosyadan belleğe yüklenir (LMA → VMA kopyası).
READONLY
Yazma korumalı; .text ve .rodata tipik örnekler.
CODE
Çalıştırılabilir talimatlar içerir.
DATA
Başlangıç değeri olan veri.
DEBUGGING
Debug bilgisi; strip edilince kaldırılır.
DİKKAT — VMA vs LMA

Embedded sistemlerde LMA (Load Memory Address) flash'taki adresi, VMA (Virtual Memory Address) RAM'deki çalışma adresini gösterir. Önyükleyici başlangıçta .data section'ını LMA'dan VMA'ya kopyalar. İkisi aynıysa normal hosted uygulama.

03 -t — symbol table

-t, ELF dosyasındaki tüm sembolleri (fonksiyonlar, global değişkenler, external referanslar) listeler.

bash
# Sembol tablosunu göster
objdump -t myapp

# Sırala ve filtrele
objdump -t myapp | sort | grep -i "func_name"

# Sadece fonksiyonları göster (F tipi)
objdump -t myapp | grep ' F '
çıktı
myapp:     file format elf32-littlearm

SYMBOL TABLE:
00010454 l    F .text  0000003c main
00010490 g    F .text  000000a8 sensor_read
00020000 g       .data  00000004 g_sensor_value
00000000         *UND*  00000000 printf
00000000         *UND*  00000000 __libc_start_main

Sütun anlamları

l / g / w
local (yerel) / global / weak sembol
F / O
Function / Object (değişken)
*UND*
Tanımsız — başka bir nesne dosyasından bağlanacak
Boyut alanı
Sembolün bayt cinsinden boyutu

04 -r — relocation entries

Relocation tablosu, linker'ın veya dinamik yükleyicinin adresleri çözümlemek için kullanacağı yer tutucuları listeler. Statik bağlama sorunlarını anlamak için kritiktir.

bash
# .o (object) dosyasındaki relocation'ları göster
objdump -r main.o

# Tam ELF'de dinamik relocation'lar için -R kullan
objdump -R myapp
çıktı — main.o
main.o:     file format elf32-littlearm

RELOCATION RECORDS FOR [.text]:
OFFSET   TYPE              VALUE
00000008 R_ARM_THM_CALL    sensor_read
00000014 R_ARM_THM_CALL    printf
00000020 R_ARM_ABS32       g_sensor_value

RELOCATION RECORDS FOR [.rodata]:
00000000 R_ARM_ABS32       .LC0

Her kayıt; offset (section içindeki konum), relocation tipi (mimariye özgü: R_ARM_THM_CALL, R_X86_64_PLT32 vb.) ve hedef sembol adını içerir. Linker bu bilgiyi kullanarak gerçek adresleri yerleştir.

05 -x — tüm header'lar

-x, tüm başlık bilgilerini tek komutla görüntüler: ELF header, section headers, symbol table ve dynamic section.

bash
# -x = --all-headers
objdump -x myapp | less

# -f = sadece dosya header özeti
objdump -f myapp
objdump -f çıktısı
myapp:     file format elf32-littlearm
architecture: arm, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00010454

# EXEC_P: çalıştırılabilir
# HAS_SYMS: sembol tablosu mevcut (strip edilmemiş)
# D_PAGED: sayfa hizalı yükleme
objdump -x — dynamic section
Dynamic Section:
  NEEDED               libpthread.so.0
  NEEDED               libc.so.6
  SONAME               libmysensor.so.1
  RPATH                /opt/sysroot/lib

06 -S — kaynak + assembly (interleaved)

-S bayrağı, DWARF debug bilgisi varsa assembly satırlarının arasına kaynak kodu satırlarını ekler. Optimizasyon sonrası kodun ne hale geldiğini görmek için idealdir.

bash
# -g ile derlenmesi gerekir (debug semboller)
arm-linux-gnueabihf-gcc -g -O1 -o sensor sensor.c

# Interleaved kaynak + assembly
arm-linux-gnueabihf-objdump -S sensor | less

# Belirli bir fonksiyon
arm-linux-gnueabihf-objdump -S sensor | \
  awk '/^[0-9a-f]+ <read_temperature>:/,/^[0-9a-f]+ <[^>]+>:/'
-S çıktı örneği
00010490 <read_temperature>:
int read_temperature(int channel) {
   10490:       b580            push    {r7, lr}
   10492:       af00            add     r7, sp, #0
    int raw = adc_read(channel);
   10494:       f7ff ffd8       bl      10448 <adc_read>
    return (raw * 330) / 4096 - 40;
   10498:       f44f 7454       mov.w   r4, #848    @ 0x350
   1049c:       fb04 f000       mul.w   r0, r4, r0
   104a0:       0c00            lsrs    r0, r0, #16
   104a2:       3fd8            subs    r7, #216    @ -40
   104a4:       4438            add     r0, r7
   104a6:       bd80            pop     {r7, pc}
DİKKAT — optimizasyon

Yüksek optimizasyon düzeylerinde (-O2, -O3) kaynak satırları ile assembly arasındaki eşleşme bozulabilir — döngüler vektörize edilir, satır içi fonksiyonlar açılır. Güvenilir eşleşme için -O0 -g ya da -Og -g kullanın.

07 --dwarf — debug bilgisi

DWARF, ELF dosyalarına gömülen standart debug formatıdır. objdump --dwarf ile debug section'larını ham olarak inceleyebilirsiniz.

bash
# Tüm DWARF section'larını göster
objdump --dwarf myapp | less

# Sadece satır numarası tablosu (.debug_line)
objdump --dwarf=decodedline myapp

# Sadece kaynak dosya isimleri
objdump --dwarf=info myapp | grep -i "DW_AT_name"

# Satır numarasından adres bul
objdump --dwarf=decodedline myapp | grep "sensor.c"
--dwarf=decodedline çıktısı
CU: sensor.c:
File name                            Line number    Starting address
sensor.c                                       1              0x10454
sensor.c                                       5              0x10458
sensor.c                                       8              0x10490
sensor.c                                      12              0x10498
sensor.c                                      15              0x104a6

Bu tablo, her kaynak satırının hangi bellek adresine karşılık geldiğini gösterir. addr2line aracı da arka planda bu tabloyu kullanır.

08 Pratik: crash adresi → assembly satırı

Embedded sistemlerde en yaygın senaryo: seri port üzerinden gelen "Segmentation fault at 0x000104b2" gibi bir mesajı kaynak koda ve assembly satırına çevirmek.

Senaryo 1: crash adresi → kaynak satırı

bash
# Hedef: crash adresinin hangi fonksiyon ve satır olduğunu bul
# Crash mesajı: "pc : [<000104b2>]"

# 1. addr2line ile kaynak satırını bul (debug binary gerekir)
arm-linux-gnueabihf-addr2line -e myapp -f 0x104b2
# read_temperature
# /home/user/project/sensor.c:12

# 2. objdump ile o adresi disassemble et
arm-linux-gnueabihf-objdump -d myapp | \
  awk '/^[[:space:]]*104[0-9a-f]+:/{print}' | \
  grep -B5 -A5 "104b2:"
çıktı
   104ac:       6800            ldr     r0, [r0, #0]    <-- r0 = NULL buraya geldi
   104ae:       fb04 f000       mul.w   r0, r4, r0
   104b2:       0c00            lsrs    r0, r0, #16     <-- CRASH BU SATIRDA
   104b4:       3fd8            subs    r7, #216
# r0 = NULL pointer dereference → ldr r0, [r0, #0] çöktü

Senaryo 2: stripped binary analizi

bash
# Üretim binary'si genellikle strip edilmiştir
file myapp_stripped
# myapp_stripped: ELF 32-bit LSB executable, ARM, stripped

# Sembol tablosu boş olacak
objdump -t myapp_stripped
# SYMBOL TABLE: no symbols

# Ancak kod hâlâ disassemble edilebilir
objdump -d myapp_stripped | head -50

# Çözüm: aynı kaynak kodu debug ile derle, adresleri eşleştir
arm-linux-gnueabihf-gcc -g -O2 -o myapp_debug sensor.c
objdump -S myapp_debug | grep -A 20 "104b0:"

# Yocto: debug paketini yükle
# IMAGE_INSTALL += "myapp-dbg"  veya  PACKAGE_DEBUG_SPLIT_STYLE

Toplu crash decode scripti

bash — crash_decode.sh
#!/bin/bash
# Kullanım: ./crash_decode.sh myapp 0x104b2 0x10498 0x10454
BINARY=$1
shift
TOOLPREFIX=${TOOLPREFIX:-arm-linux-gnueabihf-}

for ADDR in "$@"; do
    echo "=== $ADDR ==="
    ${TOOLPREFIX}addr2line -e "$BINARY" -f -i "$ADDR"
    ${TOOLPREFIX}objdump -d "$BINARY" | \
      grep -A 3 "^[[:space:]]*${ADDR#0x}:"
    echo
done
İPUCU — Yocto debug semboller

Yocto projelerinde, üretim imajındaki stripped binary ile birlikte aynı build'den üretilen -dbg paketi genellikle /usr/lib/debug/ altında .debug dosyasını içerir. objdump ve addr2line bu dosyayı otomatik olarak bulabilir: objdump -S /usr/lib/debug/usr/bin/myapp.debug