2012-08-27 16 views
6

Załóżmy, że mam plik C bez zewnętrznej zależności i tylko sekcję danych stałych. Chciałbym skompilować ten plik, a następnie uzyskać binarny obiekt blob, który można załadować w innym programie, gdzie funkcja ta będzie używana przez wskaźnik funkcji.Plik obiektowy na kod binarny

Weźmy przykład, tutaj jest fictionnal moduł binarny, f1.c

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--; 
    } 
} 

Chciałbym skompilować go f1.o, następnie f1.bin i używać go jak ten w prog .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); 
} 

Przypuszczam, że przejście z f1.c do f1.o wymaga -fPIC do uzyskania niezależności pozycji. Jakie są flagi lub skrypt linkera, które mogę użyć , aby przejść z f1.o do f1.bin?

Wyjaśnienie:

wiem o dynamicznego łączenia. dynamiczne łączenie nie jest możliwe w tym przypadku. Etap łączenia musi być rzutowany wskaźnik funkcyjny na załadowane dane, jeśli jest to możliwe.

Należy założyć, że nie ma obsługi systemu operacyjnego. Gdybym mógł, chciałbym na przykład napisać f1 w zestawie z przypisaniem do komputera.

+0

Czy wiesz, że można korzystać z udostępnionych plików obiektu? Kompilujesz plik .c do pliku .so, a następnie ładujesz go do programu 'dlopen()' i otrzymujesz funkcję function 'dlsym()' do funkcji. Potem możesz to nazwać. –

+0

Zapomnijmy o libc i dynamicznym łączeniu – shodanex

+0

Chcesz, aby stuff 'f1.bin' był ładowany dynamicznie (czyli w czasie wykonywania)? Następnie musisz zbudować wspólną bibliotekę i użyć ldopen() + ldsym() lub innego modułu ładującego (jak gmodule). Próba zrobienia tego w inny sposób może być trudna i odrzucona z powodu potencjalnych zagrożeń bezpieczeństwa (wykonanie segmentu danych i tak dalej). –

Odpowiedz

2

Należy rozważyć budowę wspólnej biblioteki (.dll dla Windows lub .so dla Linuksa).

Budowanie lib tak:

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

Jeśli chcesz, aby załadować bibliotekę z kodem dynamicznie, mają zapoznać się z funkcjami dlopen (3) i dlsym (3).

Albo jeśli chcesz połączyć bibliotekę w czasie kompilacji, budować program z

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

EDIT:

ja naprawdę nie jestem pewien, o co powiem tutaj, ale to może dać ci wskazówki do postępu w twoich badaniach ...

Jeśli nie chcesz używać dlopen i dlsym, można spróbować odczytać tablicę symboli z pliku .o w celu znalezienia adresu funkcji, a następnie mmap plik obiekt w pamięci z odczytu i wykonywania prawa. Wtedy powinieneś być w stanie wykonać załadowany kod pod podanym adresem. Ale bądź ostrożny z innymi zależnościami, które możesz napotkać w tym kodzie.

Można sprawdzić stronę podręcznika elf(5)

+0

Dokładnie nie chcę używać dynamicznego linkowania, edytowałem pytanie odpowiednio – shodanex

+0

** dlopen ** i ** dlsym ** nie implikują dynamicznego linkowania (ponieważ Twój program nie będzie połączony z biblioteką, twój plik binarny wygrał Zależy od niego, a biblioteka nie będzie konieczna podczas kompilacji). Funkcja ** dlopen ** pozwala załadować bibliotekę, a ** dlsym ** zwróci adres funkcji na podstawie podanej nazwy symbolu. – phsym

+0

dlsym oznacza wywołanie dynamicznego linkera pod systemem operacyjnym w celu analizy pliku biblioteki, wykonania mapowania itp. – shodanex

6

Przede wszystkim, jak powiedział inny należy rozważyć użycie DLL lub tak.

To powiedziawszy, jeśli naprawdę chcesz to zrobić, musisz zamienić skrypt linkera. Coś jak to (nie bardzo dobrze przetestowane, ale myślę, że to działa):

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

Następnie skompilować z:

$ gcc -c -fPIC test.c 

Linków:

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

i wyodrębnić binarny blob z :

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

Prawdopodobnie som Objaśnienie skryptu jest mile widziane:

  • ENTRY(_dummy_start) Po prostu unika ostrzeżenia o tym, że program nie ma punktu wejścia.
  • _dummy_start = 0; To definiuje symbol używany w poprzednim wierszu. Wartość nie jest używana.
  • _GLOBAL_OFFSET_TABLE_ = 0; To zapobiega kolejnemu błędowi linkera. Nie sądzę, że naprawdę potrzebujesz tego symbolu, więc można go zdefiniować jako 0.
  • .all To jest nazwa sekcji, która zbierze wszystkie bajty twojego obiektu blob. W tej próbce będą to wszystkie sekcje .text, i. Możesz potrzebować więcej, jeśli masz skomplikowane funkcje, w tym przypadku Twoim przyjacielem jest objdump -x test.o.
  • LONG(f1 - _all) Naprawdę niezbyt potrzebna, ale chcesz poznać przesunięcie swojej funkcji do kropli, czyż nie? Nie można założyć, że będzie to offset 0. W tym wierszu pierwsze 4 bajty w obszarze blob będą przesunięciem symbolu f1 (twoja funkcja). Zmień LONG z QUAD, jeśli używasz wskaźników 64-bitowych.

UPDATE: A teraz test quick'n'dirty (to działa!):

#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_' jest prawdopodobnie potrzebny, jeśli odwołanie do innych symboli (takich jak standardowa biblioteka) są zrobione. – AProgrammer

+0

@AProgrammer: Ale OP mówi wyraźnie o braku zależności zewnętrznych_, więc prawdopodobnie nie jest potrzebny.Jeśli będzie miał dostęp do dowolnej biblioteki, będzie musiał statycznie połączyć wszystkie biblioteki w obszarze blob lub sam się połączyć dynamicznie ... a to byłoby ... skomplikowane. – rodrigo

Powiązane problemy