Faqa
Faqa

Reputation: 544

Problems with calling an assembly function from C

(Running MingW on 64-bit Windows 7 and the GCC on Kubuntu)

This may possibly be just a MingW problem, but it's failed on at least one Kubuntu installation as well, so I'm doubtful.

I have a short, simple C program, which is supposed to call an assembly function. I compile the assembler using nasm and the c program using MingW's implementation of the gcc. The two are linked together with a makefile - bog-simple. And yet, linkage fails on the claim the claim that the external function is an 'undefined reference'

Relevant part of the makefile:

assign0: ass0.o main.o 
gcc -v -m32 -g -Wall -o assign0 ass0.o main.o 


    main.o: main.c 
         gcc -g -c -Wall -m32 -o main.o main.c 

    ass0.o: ass0.s
     nasm -g -f elf -w+all -o ass0.o ass0.s

The beginning of the assembly file:

section .data                       ; data section, read-write
    an:    DD 0                 ; this is a temporary var

section .text                       ; our code is always in the .text section
    global do_str               ; makes the function appear in global scope
    extern printf               

do_str:                             ; functions are defined as labels
[Just Code]

And the c file's declaration:

extern int do_str(char* a);

This has worked on at least one Kubuntu installation, failed on another, and failed on MingW. Does anyone have an idea?

Upvotes: 2

Views: 4074

Answers (2)

wallyk
wallyk

Reputation: 57784

... the claim that the external function is an 'undefined reference'

LOL! Linkers do not "claim" falsehoods. You will not convince it to change its mind by insisting that you are correct or it is wrong. Accept what the tools tell you to be the truth without delay. This is key to rapidly identifying the problem.

Almost every C compiler, including those you are using, generates global symbols with an underscore prefix to minimize name collisions with assembly language symbols. For example, change your code to

extern _printf
...
call  _printf

and error messages about printf being undefined will go away. If you do get an undefined reference to _printf, it is because the linker is not accessing the C runtime library. The link command can be challenging to get correct. Usually doing so is not very educational, so crib from a working project, or look for an example. This is way that IDEs are very helpful.

As for the C code calling the assembly function, it is usually easiest to write the assembly function using C's conventions:

    global  _do_str

_do_str:

Alternatively, you could declare the function to use the Pascal calling convention:

extern int pascal do_str ( whatever parameters are needed);
...

retval = do_str ("hello world");

The Pascal calling convention is substantially different from C's: it does not prepend a leading underscore to the symbol, the caller is responsible for removing the parameters after return, and the parameters are in a different order, possibly with some parameter data types being passed in registers rather than on the stack. See the compiler references for all the details.

Upvotes: 5

ShinTakezou
ShinTakezou

Reputation: 9681

C compilers may call the actual "function" differently, e.g. _do_str instead of do_str. Name mangling not happening always could depends on the system (and of course on the compiler). Try calling the asm function _do_str. Using proper attributes (in gcc) could also fix the problem. Also read this.

Upvotes: 2

Related Questions