Как я могу скомпилировать гибридный (asm, C) исходный код в 32-битную программу? - PullRequest
1 голос
/ 03 апреля 2019

Я использую Cygwin под Win7 на 64-битной машине.

Следующая программа без проблем компилируется в 64-битном режиме.

Makefile

runme: main.cpp asm.o
    g++ main.cpp asm.o -o executable

asm.o: asm.asm
    nasm -f elf64 asm.asm -o asm.o

asm.asm

section .data
section .bss
section .text
    global GetValueFromASM

GetValueFromASM:
    mov eax, 9
    ret

main.cpp

#include <iostream>

using namespace std;

extern "C" int GetValueFromASM();

int main()
{
    cout<<"GetValueFromASM() returned = "<<GetValueFromASM()<<endl;

    return 0;
} 

Но я хочу скомпилировать его в 32-битном режиме. Итак, я изменил elf64 на elf, и мой новый make-файл выглядит следующим образом:

Makefile

runme: main.cpp asm.o
    g++ main.cpp asm.o -o executable

asm.o: asm.asm
    nasm -f elf asm.asm -o asm.o

Но я получаю следующую ошибку:

$ make
nasm -f elf asm.asm -o asm.o
g++ main.cpp asm.o -o executable
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: i386 
architecture of input file `asm.o' is incompatible with i386:x86-64 output
collect2: error: ld returned 1 exit status
make: *** [makefile:4: runme] Error 1

В чем может быть причина?

Как мне обойти эту проблему?

Edit-1 : Я добавил опцию -m32 в g++. Теперь ошибка выглядит следующим образом:

$ make
g++ -m32 main.cpp asm.o -o executable
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libstdc++.dll.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libstdc++.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libstdc++.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libstdc++.dll.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libstdc++.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libstdc++.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libstdc++.dll.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libstdc++.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libstdc++.dll.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libstdc++.a when searching for -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lstdc++
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../libcygwin.a when searching for -lcygwin
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../libcygwin.a when searching for -lcygwin
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../libcygwin.a when searching for -lcygwin
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lcygwin
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -ladvapi32
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lshell32
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -luser32
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lkernel32
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc_s.dll.a when searching for -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lgcc_s
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0//libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-cygwin/7.4.0/libgcc.a when searching for -lgcc
/usr/lib/gcc/x86_64-pc-cygwin/7.4.0/../../../../x86_64-pc-cygwin/bin/ld: cannot find -lgcc
collect2: error: ld returned 1 exit status
make: *** [makefile:4: runme] Error 1

1 Ответ

2 голосов
/ 04 апреля 2019

Как я указал в комментарии, [SO]: Можете ли вы запустить 32-битное приложение Cygwin в 64-битной установке? (@ Ответ CristiFati) содержит много полезной информации.

Хочу начать с 2 наблюдений:

  • gcc 64bit требуется флаг -m32 (и наоборот: gcc 32bit нужен -m64 ), иначе они сгенерируют двоичные файлы, соответствующие их архитектуре CPU . Файлы объектов 32bit и 64bit ( .o ) несовместимы (при передаче компоновщику) и завершатся ошибкой
  • Cygwin (включая gcc ) использует Win формат исполняемых файлов или PE ( [Википедия ]: Переносимый исполняемый файл ). nasm форматы вывода ( elf32 и elf64 ) генерировать ELF s ( [Wikipedia] : Исполняемый и связываемый формат ). Я не знаю, как это работает (очевидно, где-то происходит преобразование формата, но я не знаю, где именно). Ради строгости, я буду использовать их Win ( win32 и win64 ), которые также работают (проверка nasm -hf)

Я тоже сталкивался с таким же поведением на Cygwin 32 (до того, как вы отредактировали вопрос):

[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q055497459]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> uname -a
CYGWIN_NT-10.0-WOW cfati-5510-0 2.11.2(0.329/5/3) 2018-11-08 14:30 i686 Cygwin
[prompt]>
[prompt]> ls
asm.asm  asm.o  builds  main.cpp  Makefile
[prompt]> make
MAKE Version 5.2  Copyright (c) 1987, 1998 Inprise Corp.
        g++  -o main.o -c  main.cpp
        g++   -o executable main.o asm.o -lstdc++
main.o:main.cpp:(.text+0x5a): undefined reference to `GetValueFromASM'
collect2: error: ld returned 1 exit status

** error 1 ** deleting executable

Я должен отметить, что у меня не установлено nasm , поэтому я построил ( 32bit ) asm.o на Cygwin 64 . Поскольку переключение между терминалами раздражает, я полностью переключился на Cygwin 64 , где у меня есть 32bit gcc ( i686-pc-cygwin-gcc ) установлено.

Я также изменил 2 ваших файла ( Makefile может быть улучшен, но сейчас это не главное).

main.cpp

#include <iostream>

using namespace std;

extern "C" int GetValueFromASM();


int main() {
    cout << "sizeof(void*): " << sizeof(void*) << endl;
    cout << "GetValueFromASM() returned: " << GetValueFromASM() << endl;

    return 0;
}

Makefile

.PHONY: all clean executable

objects = main.o asm.o
cpp = g++
cpp = i686-pc-cygwin-gcc
#m32_flag = -m32
asm_out_format = win32
#link_verbose_flag = -v

all: executable

clean:
    rm -f $(objects) executable

executable: $(objects)
    $(cpp) $(link_verbose_flag) $(m32_flag) -o $@ $(objects) -lstdc++

asm.o: asm.asm
    nasm -f $(asm_out_format) -o $@ $?

main.o: main.cpp
    $(cpp) $(m32_flag) -o $@ -c $?

После нескольких попыток я определил причину проблемы:

[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q055497459]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> uname -a
CYGWIN_NT-10.0 cfati-5510-0 3.0.5(0.338/5/3) 2019-03-31 11:17 x86_64 Cygwin
[prompt]>
[prompt]> ls
asm.asm  builds  main.cpp  Makefile
[prompt]> make
i686-pc-cygwin-gcc  -o main.o -c main.cpp
nasm -f win32 -o asm.o asm.asm
i686-pc-cygwin-gcc   -o executable main.o asm.o -lstdc++
main.o:main.cpp:(.text+0x5a): undefined reference to `GetValueFromASM'
collect2: error: ld returned 1 exit status
make: *** [Makefile:17: executable] Error 1
[prompt]>
[prompt]> nm -S asm.o | grep GetValueFromASM
00000000 T GetValueFromASM
[prompt]>
[prompt]> nm -S main.o | grep GetValueFromASM
         U _GetValueFromASM

Итак (обратите внимание на GetValueFromASM против _ GetValueFromASM несоответствие), это вопрос искажение имени (хотя сообщение об ошибке не очень полезно), которое происходит на Win ( 32bit только ).
[SO]: Добавление начальных подчеркиваний к символам сборки с помощью GCC на Win32? (ответ @ ephemient) добились цели (есть и другие решения, но они выглядят не очень красиво). Все, что вам нужно сделать, это изменить GetValueFromASM объявление на :

extern "C" int GetValueFromASM() asm ("GetValueFromASM");

и после сборки (на Cygwin 64 ):

[prompt]> uname -a
CYGWIN_NT-10.0-WOW cfati-5510-0 2.11.2(0.329/5/3) 2018-11-08 14:30 i686 Cygwin
[prompt]>
[prompt]> file executable.exe
executable.exe: PE32 executable (console) Intel 80386, for MS Windows
[prompt]> ./executable.exe
sizeof(void*): 4
GetValueFromASM() returned: 9
...