2013-01-10 9 views
5

Na przykład gdy mam:Jaka jest różnica między wersją .rodata i .rodata.str1.4 w skompilowanym pliku wyjściowym dla literałów łańcuchowych?

const char mesg [] = "Hello World"; 

jest bezpośrednio umieścić w .rodata ale kiedy mam:

const char* mesg = "Hello World"; 

go umieścić bezpośrednio w .rodata.str1.4

Jaka jest różnica między nimi i dlaczego używamy wskaźnika .rodata.str1.4, gdy używamy wskaźnika?

+0

Jakie polecenie kompilatora, wersji i kompilacji? –

+0

clang 3.5 umieszcza oba na '.rodata.str1.1' dla lokalnych literałów ciągowych,' .data' dla globali, więc nie odtwarzam ich w pełni. –

Odpowiedz

3

zrobiłem kilka eksperymentów, wygląda na to kompilator umieszcza w specjalnych sekcjach ciągi w plikach obiektowych. Ciekawa rzecz dzieje się podczas kompilacji pliku binarnego, łańcuchy kończą się w .rodata zgodnie z oczekiwaniami. Dalsze eksperymenty pokazują, że to, co się dzieje, polega na tym, że jeśli masz ten sam ciąg znaków w różnych obiektach, stają się one ujednolicone w tym samym łańcuchu w wynikowym pliku binarnym.

Podejrzewam, że powodem jest to, że kompilator chce przekazać linkerowi informacje o danych tylko do odczytu innych niż "jest tylko do odczytu", aby ostateczny link mógł podejmować bardziej inteligentne decyzje jak sobie z tym poradzić, w tym deduplikacji.

$ cat foo.c 
const char * 
fun(int i) 
{ 
     const char *foo = "foofoo foo foo foo"; 
    const char *bar = "barbar bar bar bar"; 
    return i ? foo : bar; 
} 
$ cat bar.c 
#include <stdio.h> 
extern const char *fun(int); 

int 
main(int argc, char **argv) 
{ 
    const char *foo = "foofoo foo foo foo"; 

    printf("%s%s\n", foo, fun(1)); 
    return 0; 
} 
$ cc -c -O2 foo.c 
$ cc -c -O2 bar.c 
$ objdump -s foo.o 
[...] 
Contents of section .rodata.str1.1: 
0000 62617262 61722062 61722062 61722062 barbar bar bar b 
0010 61720066 6f6f666f 6f20666f 6f20666f ar.foofoo foo fo 
0020 6f20666f 6f00      o foo. 
[...] 
$ objdump -s bar.o 
[...] 
Contents of section .rodata.str1.1: 
0000 666f6f66 6f6f2066 6f6f2066 6f6f2066 foofoo foo foo f 
0010 6f6f0025 7325730a 00     oo.%s%s.. 
[...] 
$ cc -o foobar foo.o bar.o 
$ objdump -s foobar 
[...] 
Contents of section .rodata: 
400608 01000200 00000000 00000000 00000000 ................ 
400618 62617262 61722062 61722062 61722062 barbar bar bar b 
400628 61720066 6f6f666f 6f20666f 6f20666f ar.foofoo foo fo 
400638 6f20666f 6f002573 25730a00   o foo.%s%s.. 
[...] 
+0

Dzięki za odpowiedź, mam tylko jedno małe pytanie. Czy możesz mi powiedzieć, jak widzę kolejność sekcji pliku ELF? – mehmetozer

+0

Nie wiem, czy objdump daje je w kolejności lub sortuje je w jakiś sposób. To samo z readelf. Jeśli chcesz być naprawdę pewien, przeanalizuj nagłówki ELF, to nie jest takie trudne. Nagłówki znajdują się w '/ usr/include/elf.h' na moim systemie i powinny być wszędzie podobne. W Internecie są przewodniki na temat czytania i analizowania ELF. Dlaczego chciałbyś to wiedzieć? – Art

+0

Wielkie dzięki. Chciałem tylko poznać ich kolejność. Czy to nie jest .text, .rodata, .data, .bss, .heap i .stack? – mehmetozer

2

Różne kompilatory mogą wykorzystywać różne sekcje dla danych tylko do odczytu, w zależności od rodzaju, oświadczeń itp

.rodata, zgodnie z konwencją, może być używana do niczego, które będą musiały być umieszczone w do odczytu tylko część pamięci przez program ładujący.
Więc byłoby dobrze umieścić tam znak const *.

Jednak zwykle kompilatory generują sekcje poprzedzone przedrostkiem .odata, aby skategoryzować dane tylko do odczytu.
Może to być po prostu ignorowane przez program ładujący i traktowane dokładnie tak, jak sekcja .rodata (uważam, że tak powinno być najczęściej), ale może w razie potrzeby umożliwić pewne specjalne rozmieszczenie w pamięci.

Dlatego skrypty łączące często określić .rodata i .rodata *

Powiązane problemy