clang a gcc ellen

Legalábbis valami nézeteltérés van közöttük, adott egy C forrásprogram; gcc-vel és clang-gal is működik; de ha clang-gal fordítom, és gcc-vel linkelném, akkor nem sikerül:


/usr/bin/ld: c.o: relocation R_X86_64_32S against undefined symbol `options' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output

Akkor most megpróbálom addig redukálni a programot, amíg meg nem unom. Vagy ki nem derül valami.

Szerk: Na itten van a teljes forrásprogram:


/* c.c */

int options;

int main (void)
{
    options= 0;
    return 0;
}

És a jelenség reprodukálása:


$ clang -m64 -c -o c_clang.o c.c
$ gcc -m64 -o c c_clang.o
/usr/bin/ld: c_clang.o: relocation R_X86_64_32S against undefined symbol `options' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

Érdekes kérdés még, hogy mit ért azon a gcc, hogy 'when making a shared object'
Egyébként nem hazudik, a clang-ot -fPIC opcióval hívjuk, akkor a keletkező object már tetszik a gcc/ld párosnak.

Szerk: verziószámok:


clang version 3.8.1-24 (tags/RELEASE_381/final)
gcc version 6.3.0 20170516 (Debian 6.3.0-18) 

Szerk: még azt mértem ki, hogy a derék gcc/collect2 mikor a 'ld'-t hívja, egy -pie opciót is ad neki; ezt elnyomhatjuk a gcc-nek adott -no-pie opcióval.

Szerk: egyelőre az az álláspontom, hogy a gcc-nél a '-pie' az alapértelmezés, clang-nál meg a '-no-pie' (kieg: és hasonlóan fordításkor is 'pic' illetve 'non-pic' a defaultjuk); a pie/nem-pie különbséget a 'file' így fejezi ki:


nopie:   ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked ...
pie:     ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked ...

Az objdump -f pedig:


nopie: flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED
pie:   flags 0x00000150: HAS_SYMS, DYNAMIC, D_PAGED

Assembly source összehasonlítása:


nopic:
        movl    $0, options
pic:
        movq    options@GOTPCREL(%rip), %rcx
        movl    $0, (%rcx)

Szerk: Nyilván az ASLR-miatt csinálja ezt a gcc (vagyis hogy default -fPIC/-pie opciókat használ), ezt egy kis tesztprogrammal könnyű kimutatni:


$ for i in $(seq 8); do ./d; done
main=0x55dcbf5936a0 options=0x55dcbf79402c printf=0x7fc050a86160
main=0x55b5282e26a0 options=0x55b5284e302c printf=0x7ff2c240f160
main=0x55f0bbb276a0 options=0x55f0bbd2802c printf=0x7f1bf40f0160
main=0x55973ebb46a0 options=0x55973edb502c printf=0x7ff5fdaca160
main=0x556318a6e6a0 options=0x556318c6f02c printf=0x7feb21773160
main=0x562e4bffa6a0 options=0x562e4c1fb02c printf=0x7f3c67e37160
main=0x5587a9f5d6a0 options=0x5587aa15e02c printf=0x7f4e2a797160
main=0x55de12dd06a0 options=0x55de12fd102c printf=0x7fb4ba7c8160

Hozzászólások

Yaaaay, egyszer mit meg szivtam, es pont az volt a megoldas es hallelujja.

-fPIC

Nekem 2 "nap" es egy almatlannak mondhato ejszakam banta, termeszetesen sehol nem irtak semmit a dologrol. Utalok forrast forditani, kiveve bsdn ott porttree legalabb szokott mukodni, ha tudod kezelni. :D

http://karikasostor.hu - Az autentikus zajforrás.

Kell tudni azt, hogy amit valamivel lefordítasz .o-ra, azt a .o-t a másik fordító linker része továbbvigye?
Csak azért kérdezem, mert emlékeim szerint régebben volt olyan, hogy azt sem ajánlották, ha voltak valami régebbi GCC-vel fordított .o állományaid és az új gcc-vel linkeld. Helyette rendesen fordítsd C-ből újra + linkeld az adott fordítóval.

Régesrégen kínlódtam azzal, hogy "gcc -c"-vel csak fordítsak és "ld"-vel linkeljek. Aztán a linking terén is gcc-re tértem át.