2011-08-24 17 views
17

Ben Binutils doc bakarak ... süreci ve bağlayıcı komut dosyalarını birbirine bağlayan derin anlamaya çalışıyorum ben bazı komutlar ekleyerek geliştirdik basit bağlayıcı komut uygulaması bulundu:Basit bir linker betiği nasıl kullanılır? çalıştırdığınızda yürütülebilir SIGKILL alır

OUTPUT_FORMAT("elf32-i386", "elf32-i386", 
      "elf32-i386") 
OUTPUT_ARCH(i386) 

ENTRY(mymain) 

SECTIONS 
{ 
    . = 0x10000; 
    .text : { *(.text) } 
    . = 0x8000000; 
    .data : { *(.data) } 
    .bss : { *(.bss) } 
} 

void mymain(void) 
{ 
    int a; 
    a++; 
} 

Şimdi bir yürütülebilir inşa etmeye çalıştı: Benim program çok basit bir programdır

gcc -c main.c 
ld -o prog -T my_script.lds main.o 

Ama çalışırsanız prog çalıştırın, başlatma sırasında bir SIGKILL alır. Biliyorum ki bir program derlenmiş ve komuta ile bağlanmış olması durumunda:

gcc prog.c -o prog 

son yürütülebilir ürün benim durumumda hakkında crt1.o, crti.o ve crtn.o ama ne gibi diğer nesne dosyalarının da nedir? Bu linker komut dosyalarını kullanmanın doğru yolu hangisidir?

cevap

20

Kodunuzun düzgün çalıştığından ve en sonunda sorun yaşadığından şüpheleniyorum: a++'dan sonra ne olur?

mymain(), arayana geri dönmeyi deneyecek sıradan bir C işlevidir.

Ancak, ELF giriş noktası olarak ayarladığınıza göre, ELF yükleyicisine program bölümlerini doğru yere yükledikten sonra atlayabileceğini söyler ve geri dönmenizi beklemez. Bu "crt1.o, crti.o ve gibi diğer nesne dosyaları ve" crtn.o ", bu tür C programlarında normal olarak kullanılır. Bir C programı için ELF giriş noktası, main() değil - bunun yerine, main() için uygun bir ortam oluşturan bir sarmalayıcıdır (örneğin, platforma bağlı olarak veya kayıt defterinde argc ve argv argümanlarını ayarlama), main() çağrıları (geri dönebileceği beklentisi ile) ve daha sonra exit sistem çağrısını (main()'dan geri dönüş koduyla) çağırır.


[Güncelleme aşağıdaki yorumlar:]: mymain bir kesme noktası ayarlandıktan sonra, sonra atlama Ben gdb ile örnek çalıştığınızda

, ben gerçekten mymain() dönen başarısız oluyor görüyoruz

$ gcc -g -c main.c 
$ ld -o prog -T my_script.lds main.o 
$ gdb ./prog 
... 
(gdb) b mymain 
Breakpoint 1 at 0x10006: file main.c, line 4. 
(gdb) r 
Starting program: /tmp/prog 

Breakpoint 1, mymain() at main.c:4 
4   a++; 
(gdb) display/i $pc 
1: x/i $pc 
0x10006 <mymain+6>:  addl $0x1,-0x4(%ebp) 
(gdb) si 
5  } 
1: x/i $pc 
0x1000a <mymain+10>: leave 
(gdb) si 
Cannot access memory at address 0x4 
(gdb) si 
0x00000001 in ??() 
1: x/i $pc 
Disabling display 1 to avoid infinite recursion. 
0x1: Cannot access memory at address 0x1 
(gdb) q 

: talimatlar, o zaman fonksiyon sonsözünde sorun içine alır, bu artışı gerçekleştiren görüyoruz

En azından i386 için, yüklenen kodu girmeden önce ELF yükleyici hassas bir yığın oluşturur, böylece ELF giriş noktasını bir C işlevine ayarlayabilir ve makul bir davranış elde edebilirsiniz; Ancak, yukarıda belirttiğim gibi, temiz bir proses çıkışını kendiniz halletmelisiniz. C çalışma zamanını kullanmıyorsanız, C çalışma zamanına bağlı olan herhangi bir kütüphaneyi kullanmamanız daha iyi olur.a nihai değer olarak sahip ama bilinen bir değere a sıfırlayabilirsiniz ve bir exit sistem çağrısı çağırmak için modifiye C kodu ile (satır içi montaj kullanarak) -

Yani burada orijinal bağlayıcı script kullanarak, bu bir örnektir çıkış kodu. (Not: Kullandığınız platformun tam olarak ne olduğunu söylemediniz, Linux'u burada görüyorum.)

$ cat main2.c 
void mymain(void) 
{ 
    int a = 42; 
    a++; 
    asm volatile("mov $1,%%eax; mov %0,%%ebx; int $0x80" : : "r"(a) : "%eax"); 
} 
$ gcc -c main2.c 
$ ld -o prog2 -T my_script.lds main2.o 
$ ./prog2 ; echo $? 
43 
$ 
+0

Anwser için teşekkürler Matthew. Programın başlangıçta kilitlendiğini söylüyorum çünkü gdb bunu söylüyor ... 'Ana' işlevinin daha önce çağrıldığını biliyorum, örneğin sandığım sanırım. Ama eğer 'ana' için başka bir isim yaparsam, bunu nerede belirtmeliyim? Ve eğer programımı açıkça 'ld' ile bağlarsam c çalışma zamanı nesne dosyalarını da geçmeliyim? – MirkoBanchi

+0

Neye ulaşmaya çalışıyorsunuz? Normal C çalışma zamanını ve kitaplıklarını kullanmak mı istiyorsunuz? Eğer öyleyse, ana işleviniz 'ana' olarak adlandırılmalıdır: C çalışma zamanı çağrıları budur. (Bu normalde 'crt1.o'da _start' olan ELF giriş noktasıyla aynı şey değildir.) ' ld' doğrudan çağırıyorsanız, o zaman, çeşitli C çalışma zamanı dosyalarını kendiniz bağlamanız gerekir. Eğer 'gcc' kullanıyorsanız, bunu sizin için yapacak. Gcc -v ile ne yaptığını görebiliyorsunuz, ancak 'ld' yi bir sarmalayıcı, 'topla2' ile çağırdığını bilmeniz gerekiyor (bkz. [Here] (http://gcc.gnu.org/onlinedocs/gcc) -4.6.1/gccint/Collect2.html)). –

+0

Mümkünse, c çalışma zamanı nesneleri dosyalarına bağlamadan doğru şekilde çalışan bir çalıştırılabilir (ELF formatı) oluşturulabileceğini bilirim. – MirkoBanchi

İlgili konular