2012-08-27 20 views
6

Dışsal bağımlılığı olmayan bir C dosyası var ve sadece veri bölümü yapıyorum. Bu dosyayı derlemek ve daha sonra başka bir programa yükleyebileceğim ikili bir blob almak istiyorum, burada işlev bir işlev işaretçisi aracılığıyla kullanılacaktır.Nesne dosyası ikili kod

Bir örnek verelim, işte o zaman f1.bin, f1.o için derlemek ve prog bu gibi kullanmak istiyorum

static const unsigned char mylut[256] = { 
    [0 ... 127] = 0, 
    [128 ... 255] = 1, 
}; 

void f1(unsigned char * src, unsigned char * dst, int len) 
{ 
    while(len) { 
     *dst++ = mylut[*src++]; 
     len--; 
    } 
} 

bir fictionnal ikili modül, f1.c olduğunu .c

int somefunc() { 
    unsigned char * codedata; 
    f1_type_ptr f1_ptr; 
    /* open f1.bin, and read it into codedata */ 

    /* set function pointer to beginning of loaded data */ 
    f1_ptr =(f1_type_ptr)codedata; 

    /* call !*/ 
    f1_ptr(src, dst, len); 
} 

Ben f1.o için f1.c giden varsayalım pozisyon Bağımsızlık almak için -fpic içerir. F1.o'dan f1.bin'e gitmek için 'u kullanabileceğim bayraklar veya bağlayıcı komut dosyaları nelerdir?

Açıklama:

Dinamik bağlama biliyorum. Bu durumda dinamik bağlantı mümkün değildir. Bağlama adımı, yüklüyse, cast func işaretçisi olmalıdır. Lütfen, işletim sistemi desteği olmadığını varsayalım. Yapabilseydim, örneğin PC ile ilgili adresleme ile birlikte yazım f1 yazarım.

+0

Eğer paylaşılan nesne dosyaları kullanabilirsiniz biliyor musunuz? .c dosyasını bir .so dosyasına derlersiniz, daha sonra 'dlopen()' programına yüklersiniz ve 'dlsym()' fonksiyonuna fonksiyon göstergesini alırsınız. O zaman arayabilirsin. –

+0

Libc ve dinamik bağlantıyı unutmayalım – shodanex

+0

'f1.bin' thingie'nin dinamik olarak yüklenmesini istersiniz (örneğin çalışma zamanında)? Sonra paylaşılan bir kütüphane kurmanız ve ldopen() + ldsym() veya diğer modül yükleyicisini (gmodule gibi) kullanmanız gerekir. Bunu başka bir şekilde yapmaya çalışmak, olası güvenlik tehditleri (veri segmentini yürütme vb.) Nedeniyle sert ve reddedilebilir. –

cevap

2

Sen (linux için .bu .dll pencereler için veya ) paylaşılan kitaplık oluşturmayı düşünmesi gerekir.

böyle lib oluşturun:

gcc -c -fPIC test.c 
gcc -shared test.o -o libtest.so 

size kodundan dinamik kütüphane yüklemek isterseniz, işlevler dlopen bakabilirsiniz (3) ve dlsym (3).

Ya sen ile program derleme zamanında kütüphane bağlamak kurmak istiyorsanız

gcc -c main.c 
gcc main.o -o <binary name> -ltest 

DÜZENLEME: Gerçekten ben ne diyecekler emin değilim

Burada, ancak bu sizin araştırmalarınızda ilerleme için bir ipucu verebilir ...

dlsym Dlopen ve , işlevin adresini bulmak için .o dosyadan sembol tablosunu okumak için deneyebilirsiniz, sonra, mmap okuma ile bellekte nesne dosyası ve hakları yürütün. Ardından, bulduğunuz adreste yüklü kodu çalıştırabilmelisiniz. Ancak bu kodda karşılayabileceğiniz diğer bağımlılıklara dikkat edin. Diğer bir DLL veya SO kullanmayı düşünmelisiniz söylediğiniz gibi, adam sayfasını tüm elf(5)

+0

Dinamik bağlantıyı kullanmak istemiyorum, soruyu şu şekilde düzenledim – shodanex

+0

** dlopen ** ve ** dlsym ** dinamik bağlantı anlamına gelmiyor (programınız kitaplığa bağlı olmayacağından ona bağlı ve derleme sırasında kütüphane gerekli olmayacaktır. ** dlopen ** işlevi bir kütüphane yüklemenizi sağlar ve ** dlsym ** sağladığınız sembol ismine göre fonksiyon adresini döndürür. – phsym

+0

dlsym, kütüphane dosyasını analiz etmek için işletim sistemi tarafından sağlanan dinamik bağlayıcıyı çağırmak, eşleme yapmak vb. Demek anlamına gelir. – shodanex

6

Önce kontrol edebilirsiniz

.

Bunu yapmak isterseniz, linker komut dosyasını değiştirmeniz gerekir. Böyle bir şey (çok iyi test edilmedi, ama çalıştığını düşünüyorum):

$ gcc -c -fPIC test.c 

Bağlantı ile:

ENTRY(_dummy_start) 
SECTIONS 
{ 
    _dummy_start = 0; 
    _GLOBAL_OFFSET_TABLE_ = 0; 
    .all : { 
     _all = .; 
     LONG(f1 - _all); 
     *(.text .text.* .data .data.* .rodata .rodata.*) 
    } 
} 

Sonra ile derlemek

$ ld -T script.ld test.o -o test.elf 

Ve ile ikili damla ayıklamak :

$ objcopy -j .all -O binary test.elf test.bin 

Muhtemelen som Sadece programın bir giriş noktası olmaması konusunda uyarı önler

  • ENTRY(_dummy_start): script e açıklaması açığız.
  • _dummy_start = 0; Bu, önceki satırda kullanılan sembolü tanımlar. Değer kullanılmıyor.
  • _GLOBAL_OFFSET_TABLE_ = 0; Başka bir bağlayıcı hatası önler. Bu simgeye gerçekten ihtiyacınız olduğunu düşünmüyorum, bu yüzden 0 olarak tanımlanabilir.
  • .all Blobunuzun tüm baytlarını toplayacak bölümün adı budur. Bu örnekte, tüm .text, .data ve .rodata bölümleri birlikte olacaktır. Karmaşık fonksiyonlarınız varsa biraz daha fazlasına ihtiyacınız olabilir, bu durumda objdump -x test.o arkadaşınız.
  • LONG(f1 - _all) Gerçekten gerekli değil, ancak işlevinizin blobunuzdaki sapmasını bilmek istersiniz, değil mi? Ofset 0'da olacağını varsayamazsınız. Bu satırda blobdaki ilk 4 bayt f1 sembolünüzün (fonksiyonunuz) ofsetidir. 64-bit işaretçileri kullanıyorsanız LONG'u QUAD ile değiştirin.

GÜNCELLEME: Ve şimdi bir quick'n'dirty testi (çalışıyor!):

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/mman.h> 

typedef void (*f1_t)(char *a, char *b, int len); 
f1_t f1; 

int main() 
{ 
    char *blob = (char*)valloc(4096); 
    FILE *f = fopen("test.bin", "rb"); 
    fread(blob, 1, 4096, f); 
    fclose(f); 

    unsigned offs = *(unsigned*)blob; 
    f1 = (f1_t)(blob + offs); 
    mprotect(blob, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); 
    char txt[] = "¡hello world!"; 
    char txt2[sizeof(txt)] = ""; 
    f1(txt, txt2, sizeof(txt) - 1); 
    printf("%s\n%s\n", txt, txt2); 
    return 0; 

} 
+0

'_GLOBAL_OFFSET_TABLE_ ' yapıldı. – AProgrammer

+0

@AProgrammer: Ancak OP özellikle _no harici bağımlılık_ diyor, bu nedenle muhtemelen gerekli değildir.Eğer herhangi bir kütüphaneye erişirse, tüm kütüphaneleri blobta statik olarak bağlamalı veya dinamik bağlantıyı kendisi yapmalıdır ... ve bu karmaşık olurdu. – rodrigo

İlgili konular