2

I am using Cygwin under Win7 in a 64-bit machine.

The following program compiles in 64-bit mode without any issue.

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;
} 

But, I want to compile it in 32-bit mode. So, I changed elf64 to elf and my new makefile looks like the following:

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

But, I am getting the following error:

$ 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

What could be the reason?

How can I get around this issue?

Edit-1: I have added -m32 option in g++. Now, the error is as follows:

$ 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
CristiFati
  • 38,250
  • 9
  • 50
  • 87
user366312
  • 16,949
  • 65
  • 235
  • 452
  • 2
    You need to tell g++ as well that you want 32 bit output. Add `-m32` option. – Jester Apr 03 '19 at 14:24
  • @Jester, adding `-m32` is giving even bigger error. – user366312 Apr 03 '19 at 14:27
  • 1
    64-bit MINGW does not support generating 32-bit executable files that simply. A lot of library files are missing... – Martin Rosenau Apr 03 '19 at 14:41
  • 1
    You will need to install the 32 bit cygwin stuff. – Jester Apr 03 '19 at 14:48
  • If you want to get the libraries the easy way, here is my suggestion: Remove cygwin and Install msys2 from msys2.org run in msys2 shell: "pacman -S base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain mingw-w64-x86_64-nasm" Add the following to path: "C:\msys64\usr\bin" and depending on which you want default "C:\msys64\mingw64\bin" or "C:\msys64\mingw32\bin" Also it is easy to update, just run "pacman -Syu" from time to time. – nulleight Apr 03 '19 at 15:21
  • @nulleight, hmmm....good info. Let me try. – user366312 Apr 03 '19 at 15:37
  • You can search packages and libs to install with "pacman -Ss " You can also install nano editor or mc (midnight commander) if you are a linux user and have to use windows. Also when you install make, you have to call it with "mingw32-make" instead of just make. There are also alot of libraries and tools like python with both 64 and 32 bit installable side by side. – nulleight Apr 03 '19 at 16:26
  • Where did you get *nasm*? What about installing *32bit* *Cygwin* as well? Check https://stackoverflow.com/questions/54206577/can-you-run-a-32-bit-cygwin-application-in-a-64-bit-installation/54216105#54216105. – CristiFati Apr 03 '19 at 18:23
  • @CristiFati, In Cygwin64. – user366312 Apr 03 '19 at 18:23
  • Sure, I've also checked *setup.exe* (should have done it before posting the comment). – CristiFati Apr 03 '19 at 18:26

1 Answers1

2

As I pointed it out in the comment, [SO]: Can you run a 32 bit Cygwin application in a 64 bit installation? (@CristiFati's answer) contains lots of useful info.

I want to start with 2 observations:

  • gcc 64bit needs the -m32 flag (and viceversa: gcc 32bit needs -m64), otherwise they will generate binaries that match their CPU architecture. 32bit and 64bit object (.o) files are incompatible (when passed to the linker) and it will fail
  • Cygwin (including gcc) uses Win executables format or PE ([Wikipedia]: Portable Executable). nasm's output formats (elf32 and elf64) generate ELFs ([Wikipedia]: Executable and Linkable Format). I don't know how this works (well obviously, somewhere a format conversion takes place, but I don't know where exactly). For rigorousity's sake, I'll be using their Win counterparts (win32 and win64) which work as well (check nasm -hf)

I too encountered the same behavior on Cygwin 32 (before you edited the question):

[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

I must mention that I don't have nasm installed here, so I've built (the 32bit) asm.o on Cygwin 64. Since switching between terminals is annoying, I completely switched to Cygwin 64, where I have the 32bit gcc (i686-pc-cygwin-gcc) installed.

I've also modified 2 of your files (Makefile can be improved a lot, but that's not the main focus now).

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 $?

After a few attempts, I identified the cause of the problem:

[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

So (notice the GetValueFromASM vs. _GetValueFromASM mismatch), it's a matter of name mangling (although the error message is not very helpful) that happens on Win (32bit only).
[SO]: Adding leading underscores to assembly symbols with GCC on Win32? (@ephemient's answer) did the trick (there are other solutions, but they don't look very nice). All you need to do is changing GetValueFromASM's declaration to:

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

and after building (on 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
CristiFati
  • 38,250
  • 9
  • 50
  • 87