MinGW Win32 + nasm: "undefined link"
I am currently developing an OS for educational purposes and it still works. Then I tried to call the assembler function, compiled with nasm, -fwin32
, from C code, but all I got was an "undefined reference" error. I created a small example in pure assembler that has the same problem, but is easy to understand and small: It includes two files:
test.asm:
[bits 32]
global _testfunc
_testfunc:
ret
test2.asm:
[bits 32]
extern _testfunc
global _testfunc2
_testfunc2:
call _testfunc
ret
Here is my compiler / linker script (using windows batch files):
nasm.exe -f win32 test.asm -o test.o
nasm.exe -f win32 test2.asm -o test2.o
ld test.o test2.o -o output.tmp
This results in an error:
test2.o:test2.asm:(.text+0x1): undefined reference to `testfunc'
To expand on the question, the same happens when the function is called from C:
test.c:
extern void testfunc(void);
void start()
{
testfunc();
}
With this linker script:
gcc -ffreestanding -c test.c -o testc.o
nasm.exe -f win32 test.asm -o test.o
ld test.o testc.o -o output.tmp
In test.o, test2.o and testc.o it always says _testfunc
, so the error has nothing to do with leading underscores!
source to share
In my MinGW setup, you need a directive section
before the code.
; foo.asm
[bits 32]
global _testfunc
section .text
_testfunc:
ret
Then create win32 format:
nasm -fwin32 foo.asm -o foo.o
Now you can check what testfunc
is there:
$ nm foo.o
00000000 a .absolut
00000000 t .text
00000001 a @feat.00
00000000 T _testfunc
T
means the text section is global, so we're good to go.
Note. I would not name anything test
as it is a shell command. It can cause endless grief.
C function as you showed it, but name the file something else:
// main.c
extern void testfunc(void);
int main(void)
{
testfunc();
return 0;
}
Then we gcc
do the heavy lifting to create the let executable, because ld
sometimes a secret argument is required.
gcc -ffreestanding main.c foo.o -o main
source to share
Your missing something is important, your code is not in the code section!
Your asm files should look like this:
test.asm
global _testfunc
section .text ; <<<< This is important!!!
; all code goes below this!
_testfunc:
ret
test2.asm
extern _testfunc
global _testfunc2
section .text ; <<<< Again, this is important!!!
_testfunc2:
call _testfunc
ret
source to share