0

I'm trying to build hello.asm into a Windows executable, but when I use the suggested commands for assembling, linking, and compiling the code, I get errors. Whether I'm using Strawberry Perl's GCC or MinGW's GCC, both give errors for the same YASM/NASM code.

Here are the traces. Either I'm doing something wrong in my Makefile or .ASM, or the linking process is buggy. Either way, I'd like someone to help me resolve the errors.

I get the same result whether I use nasm or yasm to assemble the object file.

Strawberry Perl GCC Trace:

C:\> make
nasm -f win32 -l hello.lst hello.asm
gcc -o hello hello.o
ld: cannot find crt1.o: No such file or directory
ld: cannot find -lmingw32
ld: cannot find -lgcc
ld: cannot find -lmoldname
ld: cannot find -lcrtdll
ld: cannot find -luser32
ld: cannot find -lkernel32
ld: cannot find -ladvapi32
ld: cannot find -lshell32
ld: cannot find -lmingw32
ld: cannot find -lgcc
ld: cannot find -lmoldname
ld: cannot find -lcrtdll
make: *** [hello] Error 1

MinGW GCC Trace:

$ make
gcc -o hello hello.o
c:/mingw/bin/../lib/gcc/mingw32/4.5.2/../../../libmingw32.a(main.o):main.c:(.text+0x104): undefined reference to `WinMain@16'
collect2: ld returned 1 exit status
make: *** [hello] Error 1

Specs:

  • YASM 1.2.0
  • NASM 2.10.05
  • Strawberry Perl gcc 4.4.3
  • MinGW gcc 4.5.2
  • Strawberry Perl 5.12
  • MinGW 0.1
  • Windows 7 Professional x64
  • MacBook Pro 2009
mcandre
  • 22,868
  • 20
  • 88
  • 147
  • What OS? I see you have Win7 and MAC listed. For windows, use GoLink as the linker. Did you export your start label? – Gunner Sep 20 '12 at 02:11
  • I'd like to use `ld` or `gcc` for linking; GCC is more multiplatform, available for Windows via the MinGW installer. – mcandre Sep 20 '12 at 02:38
  • @Gunner, I am currently using Windows 7, though I like to dual boot, so I'm on MacBook Pro hardware. And I want to be able to assemble and link the same YASM/NASM code no matter which OS I'm using, because YASM and NASM are multiplatform. – mcandre Sep 20 '12 at 02:40
  • Actually no. The assembler/linker is multiplatform, but the code you write isn't... – Toribio Sep 20 '12 at 02:45
  • @FlávioToribio, could you show code that would work on both Windows and Linux? – mcandre Sep 20 '12 at 02:50
  • @mcandre, AFAIK, that's not possible, [see this question](http://stackoverflow.com/q/3715467/260411) – Toribio Sep 20 '12 at 02:54
  • Certainly is possible! Here is a tut I wrote using nasm and gtk. Works on linux and windows www.dreamincode.net/forums/topic/292403-nasm-cross-os-app-for-linuxwindows-using-gtk/ – Gunner Sep 20 '12 at 03:19
  • This is a nice tutorial, but you didn't use instructions and registers that are OS-specific, which I think Assembly has the most... The `push`, `pop`, `add`, `lea`, `mov`, `call`, etc just happen to be equal for the two OS's, and you're happening to use a multiplatform library, but for example if you try to open the CD-ROM jack, you'd have to use different functions, libraries, interruptions, etc... – Toribio Sep 20 '12 at 03:28
  • @FlávioToribio, you can still get around this with preprocessors, if the build process is anything like C's. – mcandre Sep 20 '12 at 04:16
  • @Gunner, that's an awesome tutorial! I like how you use a single Makefile for multiple operating systems. Would you consider posting a simpler one that just prints "Hello World" in Windows, Mac, and Linux? I'd be especially grateful if you showed how to do this with the GCC toolchain in all of these, rather than requiring MSVC++ for Windows. – mcandre Sep 20 '12 at 04:22
  • @Flávio sure you could write cross os code that uses conditional Assembly, but that is a nightmare to update and bugfix. Using a Multiplatform library is the way to go. I can most certainly eject a CD tray on windows and Linux using GIO from GTK. Explain what registers are OS specific? – Gunner Sep 21 '12 at 01:04

3 Answers3

4

Replace your main() function with label _WinMain@16 like this:

main.asm

    section .text
    extern  _foo

;--------------------------------------------------
; main()
; 在 Win32 環境下, _WinMain@16 為程式進入點
;--------------------------------------------------

    global  _WinMain@16
_WinMain@16:
    ; foo(2,3)
    ; 呼叫時, 參數為堆疊順序 (先進後出)
    push    DWORD 3     ; b=3
    push    DWORD 2     ; a=2
    call    _foo

    ; 堆疊復原
    pop     eax
    pop     eax
    ret

foo.c

    #include <stdio.h>

    void foo(int a, int b) {
         printf("%d + %d = %d\n", a, b, a+b);
    }

Makefile

all:
    rm -f *.o
    gcc -c foo.c
    nasm -f win32 -o main.o main.asm
    gcc -o main.exe main.o foo.o
Echilon
  • 10,064
  • 33
  • 131
  • 217
Raymond Wu
  • 314
  • 2
  • 6
1

A solution in several parts:

  1. A strange thing was happening: When I manually type gcc ... to build the executables, I get few link errors. But when I used make to run the exact same command, I got all kinds of link errors. It turns out that Free Pascal's make.exe was shadowing the proper make.exe. You can either fix this by promoting the proper directory in PATH, or uninstalling the offending application. I didn't have much use for Pascal, so I uninstalled it and suddenly gcc started working better.

  2. Windows NASM/YASM assembly requires prefixing function names with underscore (_). In order to keep the assembly code multiplatform, omit the underscores in the code, and use a Makefile option to tell nasm/yasm to prefix with an underscore when building in Windows.

  3. Building with a manual ld call to link the stuff together in Windows does not work. Substituting gcc fixed the odd "undefined printf" link errors, because GCC somehow knows how to sort this out.

  4. It's difficult to properly exit a program, espcially in a multiplatform way. One way is to set eax to zero and then return.

All of this is reflected in working versions of hello.asm for NASM and YASM, at GitHub.

mcandre
  • 22,868
  • 20
  • 88
  • 147
0

For a simple windows console hello: hello.asm

extern  printf, ExitProcess

SECTION     .data
szHello db  "Hello there!", 0

SECTION     .text
StartHello:
    push    szHello
    call    printf
    add     esp, 4 

    push    0
    call    ExitProcess 

makefile:

hello: hello.obj
    GoLink.exe  /console /entry StartHello hello.obj kernel32.dll msvcrt.dll  

hello.obj: hello.asm
    nasm -f win32 hello.asm -o hello.obj
Gunner
  • 5,780
  • 2
  • 25
  • 40
  • The *Hello World* he is trying to compile uses interrupt calls, not C libraries to print the message... – Toribio Sep 20 '12 at 02:33
  • Well you cannot use linux interrupts on windows which his linked code uses – Gunner Sep 20 '12 at 02:39
  • Exactly, that's why I don't have an answer for him. He's trying to compile a code for Linux, but says he's using Windows, and even try to compile in elf... – Toribio Sep 20 '12 at 02:43
  • @FlávioToribio, yes, `elf` was the wrong format. I've since changed the Makefile to choose the right format for the current computer. https://github.com/mcandre/mcandre/blob/master/yasm/hello/Makefile – mcandre Sep 20 '12 at 04:29