Я пытаюсь скомпилировать исходный код с помощью tcc (версия 0.9.26) для файла .o, сгенерированного gcc, но он ведет себя странно. GCC (версия 5.3.0) взят из 64-разрядной версии MinGW.
В частности, у меня есть следующие два файла (te1.c te2.c). Я сделал следующие команды в окне Windows7
c:\tcc> gcc -c te1.c
c:\tcc> objcopy -O elf64-x86-64 te1.o #this is needed because te1.o from previous step is in COFF format, tcc only understand ELF format
c:\tcc> tcc te2.c te1.o
c:\tcc> te2.exe
567in dummy!!!
Обратите внимание, что он отрезал 4 байта от строки 1234567in dummy!!!\n
. Интересно, что могло пойти не так?
Спасибо Джин
========файл te1.c===========
#include <stdio.h>
void dummy () {
printf1("1234567in dummy!!!\n");
}
========файл te2.c===========
#include <stdio.h>
void printf1(char *p) {
printf("%s\n",p);
}
extern void dummy();
int main(int argc, char *argv[]) {
dummy();
return 0;
}
Обновление 1
Увидел разницу в сборке между te1.o (te1.c, скомпилированный tcc) и te1_gcc.o (te1.c, скомпилированный gcc). В скомпилированном tcc я увидел lea -0x4(%rip),%rcx
, в скомпилированном gcc я увидел lea 0x0(%rip),%rcx
. Не уверен, почему.
C:\temp>objdump -d te1.o
te1.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <dummy>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 81 ec 20 00 00 00 sub $0x20,%rsp
b: 48 8d 0d fc ff ff ff lea -0x4(%rip),%rcx # e <dummy+0xe>
12: e8 fc ff ff ff callq 13 <dummy+0x13>
17: c9 leaveq
18: c3 retq
19: 00 00 add %al,(%rax)
1b: 00 01 add %al,(%rcx)
1d: 04 02 add $0x2,%al
1f: 05 04 03 01 50 add $0x50010304,%eax
C:\temp>objdump -d te1_gcc.o
te1_gcc.o: file format pe-x86-64
Disassembly of section .text:
0000000000000000 <dummy>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 20 sub $0x20,%rsp
8: 48 8d 0d 00 00 00 00 lea 0x0(%rip),%rcx # f <dummy+0xf>
f: e8 00 00 00 00 callq 14 <dummy+0x14>
14: 90 nop
15: 48 83 c4 20 add $0x20,%rsp
19: 5d pop %rbp
1a: c3 retq
1b: 90 nop
1c: 90 nop
1d: 90 nop
1e: 90 nop
1f: 90 nop
Обновление 2
С помощью бинарного редактора я изменил машинный код в te1.o (созданном gcc) и изменил lea 0(%rip),%rcx
на lea -0x4(%rip),%rcx
, и, используя tcc, чтобы связать его, полученный exe-файл работает нормально. Точнее, я сделал
c:\tcc> gcc -c te1.c
c:\tcc> objcopy -O elf64-x86-64 te1.o
c:\tcc> use a binary editor to the change the bytes from (48 8d 0d 00 00 00 00) to (48 8d 0d fc ff ff ff)
c:\tcc> tcc te2.c te1.o
c:\tcc> te2
1234567in dummy!!!
Обновление 3
В соответствии с просьбой, вот вывод objdump -r te1.o
C:\temp>gcc -c te1.c
C:\temp>objdump -r te1.o
te1.o: file format pe-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
000000000000000b R_X86_64_PC32 .rdata
0000000000000010 R_X86_64_PC32 printf1
RELOCATION RECORDS FOR [.pdata]:
OFFSET TYPE VALUE
0000000000000000 rva32 .text
0000000000000004 rva32 .text
0000000000000008 rva32 .xdata
C:\temp>objdump -d te1.o
te1.o: file format pe-x86-64
Disassembly of section .text:
0000000000000000 <dummy>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 20 sub $0x20,%rsp
8: 48 8d 0d 00 00 00 00 lea 0x0(%rip),%rcx # f <dummy+0xf>
f: e8 00 00 00 00 callq 14 <dummy+0x14>
14: 90 nop
15: 48 83 c4 20 add $0x20,%rsp
19: 5d pop %rbp
1a: c3 retq
1b: 90 nop
1c: 90 nop
1d: 90 nop
1e: 90 nop
1f: 90 nop
tcc
иgcc
имеют разные соглашения о вызовах по умолчанию. Может захочется это проверить. - person Captain Obvlious   schedule 12.07.2016te1.c
иметьextern void printf1(char *p);
или включать заголовок, объявляющийprintf()
? - person RastaJedi   schedule 12.07.2016extern void dummy();
должно бытьextern void dummy(void);
, иначеmain()
может вызватьdummy(1,2,3)
без предупреждения/ошибки. - person chux - Reinstate Monica   schedule 12.07.2016extern void printf1(char *p);
, но это ничего не изменило. Спасибо, что указалиextern void dummy(void);
Попробовал, но безрезультатно. - person packetie   schedule 12.07.2016readelf -r te1.o
)? Вы пытались скомпилировать te2.c с помощью tcc, но связать с gcc? Возможны три случая: 1) te1.o неверен 2) tcc-linker делает что-то не так, 3) что-то еще. Было бы неплохо исключить 1+2.. - person ead   schedule 16.07.2016printf1(..)
он перевел его вlea -0x4(%rip),%rcx
. Обратите внимание на-4
? Это объясняет, если tcc связывает te1.o, скомпилированный с помощью gcc, то в указателе на константную строку отстает 4 байта. Да, я тестировал его на Linux, и tcc и gcc тоже хорошо работали вместе. Мой linux gcc версии (4.8.4) отличается от версии для Windows (5.3.0).objdump -d
показано, что эти две версии gcc генерируют разный код. - person packetie   schedule 16.07.2016readelf -r te1.o
)? -4 может иметь значение только тогда, когда мы знаем перемещение. В linux gcc использует релокацию R_X86_64_32, а tcc R_X86_64_PC32, может тут что-то перепутал. Я также попытался бы связать с другим компоновщиком (не tcc). - person ead   schedule 16.07.2016objdump -r te1.o
. Не знаю, ошибся ли tcc, но он определенно делает что-то другое, как видно из кода сборкиlea -4(%rip), %rcx
, который он генерирует. - person packetie   schedule 17.07.2016000000000000000b R_X86_64_PC32 .rdata-4
- person ead   schedule 17.07.2016