странное поведение при попытке скомпилировать исходный код с помощью tcc для файла .o, сгенерированного gcc

Я пытаюсь скомпилировать исходный код с помощью 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, Интересно, что могло пойти не так?

Спасибо
Jin

======== файл 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-64Disassembly 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-64Disassembly 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

Update2

Используя бинарный редактор, я изменил машинный код в 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     printf1RELOCATION RECORDS FOR [.pdata]:
OFFSET           TYPE              VALUE
0000000000000000 rva32             .text
0000000000000004 rva32             .text
0000000000000008 rva32             .xdataC:\temp>objdump -d te1.o

te1.o:     file format pe-x86-64Disassembly 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

10

Решение

Не имеет ничего общего с tcc или вызов соглашения. Это связано с различными соглашениями компоновщика для elf64-x86-64 and pe-x86-64 форматы.

При использовании PE компоновщик неявно вычитает 4 для вычисления окончательного смещения.

С ELF он этого не делает. Из-за этого 0 является правильным начальным значением для PE, а -4 является правильным для ELF.

К несчастью, objcopy не конвертирует это -> ошибка в objcopy,

6

Другие решения

добавлять

extern void printf1(char *p);

в ваш файл te1.c

Или: компилятор примет аргумент 32-битное целое число, так как нет прототипа, а указатели имеют 64-битную длину.

Изменить: это все еще не работает. Я обнаружил, что функция никогда не возвращается (поскольку повторный вызов printf1 ничего не делает!). Кажется, что 4 первых байта потребляются как адрес возврата или что-то в этом роде. В 32-битном режиме gcc работает нормально.
Похоже, проблема соглашения о вызовах для меня, но до сих пор не могу понять это.
Еще одна подсказка: звонить printf от te1.c side (gcc, используя привязки tcc stdlib) вылетает с segv.

Я разобрал исполняемый файл. Первая часть — повторный вызов со стороны tcc.

  40104f:       48 8d 05 b3 0f 00 00    lea    0xfb3(%rip),%rax        # 0x402009
401056:       48 89 45 f8             mov    %rax,-0x8(%rbp)
40105a:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
40105e:       e8 9d ff ff ff          callq  0x401000
401063:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
401067:       e8 94 ff ff ff          callq  0x401000
40106c:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
401070:       e8 8b ff ff ff          callq  0x401000
401075:       48 8b 4d f8             mov    -0x8(%rbp),%rcx
401079:       e8 82 ff ff ff          callq  0x401000
40107e:       e8 0d 00 00 00          callq  0x401090
401083:       b8 00 00 00 00          mov    $0x0,%eax
401088:       e9 00 00 00 00          jmpq   0x40108d
40108d:       c9                      leaveq
40108e:       c3                      retq

Вторая часть повторяется (6 раз) вызовом той же функции. Как видите, адрес другой (сдвинут на 4 байта, как ваши данные) !!! Это работает только один раз, потому что 4 первых инструкции следующие:

 401000:       55                      push   %rbp
401001:       48 89 e5                mov    %rsp,%rbp

так что стек уничтожается, если те пропущены !!

  40109f:       48 89 45 f8             mov    %rax,-0x8(%rbp)
4010a3:       48 8b 45 f8             mov    -0x8(%rbp),%rax
4010a7:       48 89 c1                mov    %rax,%rcx
4010aa:       e8 55 ff ff ff          callq  0x401004
4010af:       48 8b 45 f8             mov    -0x8(%rbp),%rax
4010b3:       48 89 c1                mov    %rax,%rcx
4010b6:       e8 49 ff ff ff          callq  0x401004
4010bb:       48 8b 45 f8             mov    -0x8(%rbp),%rax
4010bf:       48 89 c1                mov    %rax,%rcx
4010c2:       e8 3d ff ff ff          callq  0x401004
4010c7:       48 8b 45 f8             mov    -0x8(%rbp),%rax
4010cb:       48 89 c1                mov    %rax,%rcx
4010ce:       e8 31 ff ff ff          callq  0x401004
4010d3:       48 8b 45 f8             mov    -0x8(%rbp),%rax
4010d7:       48 89 c1                mov    %rax,%rcx
4010da:       e8 25 ff ff ff          callq  0x401004
4010df:       48 8b 45 f8             mov    -0x8(%rbp),%rax
4010e3:       48 89 c1                mov    %rax,%rcx
4010e6:       e8 19 ff ff ff          callq  0x401004
4010eb:       90                      nop
5

По вопросам рекламы [email protected]