2

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

Faqa
  • 550
  • 5
  • 15
  • 2
    Sometimes an `_` gets prepended to symbol names. What's the exact error message you get? – Carl Norum Mar 21 '12 at 17:45
  • possible duplicate of [Adding leading underscores to assembly symbols with GCC on Win32?](http://stackoverflow.com/questions/1034852/adding-leading-underscores-to-assembly-symbols-with-gcc-on-win32) – Carl Norum Mar 21 '12 at 17:46
  • Have you tried swapping {ass0.o main.o} on the linker command line? – wildplasser Mar 21 '12 at 17:46
  • 1
    @wildplasser, why should that make a difference? – Carl Norum Mar 21 '12 at 17:47
  • @wildplasser - Yes, I did. No dice. – Faqa Mar 21 '12 at 17:48
  • Well, in the case of libraries, the files are searched left to right. Maybe someone thought this would be a good idea for objects, too. – wildplasser Mar 21 '12 at 17:49
  • @CarlNorum - I tried adding a _ to the beginning on the C side. My exact error is 'undefined reference to `do_str' - on the line in which it tries to *invoke* do_str. – Faqa Mar 21 '12 at 17:49
  • 2
    You want to add the `_` on the assembly side, not the C side, if that's in fact the problem. There can't be an 'undefined reference' error related to a source code line - it's a link error. Please copy and paste the full text here. – Carl Norum Mar 21 '12 at 17:50
  • @wildplasser, search order might be a problem if there were multiply defined symbols and the OP was finding the wrong one to be linked, but I don't think it affects *missing* symbols. – Carl Norum Mar 21 '12 at 17:56
  • Turned out to indeed be a mangling problem. Changing the asm's definition to include an _ is what worked. – Faqa Mar 21 '12 at 18:19
  • The solution is not to rename the assembler function, but to add another symbol so you have both `do_str` and `_do_str` in your assembler file. – Some programmer dude Mar 21 '12 at 18:43

2 Answers2

5

... 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.

wallyk
  • 56,922
  • 16
  • 83
  • 148
2

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.

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39