简体   繁体   中英

Calling assembly routines from C source code

I have this simple C source code :

#include <stdio.h>

extern int Sum(int,int);

int main()
{
  int a,b,s;
  a=1 , b=2;
  s = Sum(a,b);
  return 0;
}

and i have this s.asm which defines the function _Sum :

global _Sum

     _Sum:

        push    ebp             ; create stack frame
        mov     ebp, esp
        mov     eax, [ebp+8]    ; grab the first argument
        mov     ecx, [ebp+12]   ; grab the second argument
        add     eax, ecx        ; sum the arguments
        pop     ebp             ; restore the base pointer
        ret

now , i compiled the .asm using :

nasm s.asm -f elf -o s.o

and compiled and linked the .c file using :

gcc s.o test.o -o testapp

this is the outcome :

/tmp/ccpwYHDQ.o: In function `main':
test.c:(.text+0x29): undefined reference to `Sum'
collect2: ld returned 1 exit status

So what is the problem ?

I'm using Ubuntu-Linux

Any help would be greatly appreciated , Thanks

[SOLVED] : i checked with nm the test.o file and it expected to find the symbol 'Sum' not '_Sum' so changing that solved the problem.

In typical assemblers, labels are by default local. To tell the assembler to make them visible to external routines, you must add a declaration, such as:

.globl _Sum

Additionally, declare the routine correctly in C. This is not the cause of your link error but can cause other problems:

extern int Sum(int, int);

For completeness, with thanks to the commenters: Do not overwrite your object files. You can assemble, compile, and link with:

nasm s.asm -f elf -o s.o
gcc test.c s.o -o test

(This names the executable “test”, and you will probably have to execute it with “./test” to distinguish the “test” in your directory from the “test” command. You may be happier choosing another name.)

For educational purposes: If you have the nm tool on your system, execute the command nm so . It may show you something like:

00000000 t _Sum

The t means that _Sum is a local label in the code section. (The code section is also called the text section, hence the t.) Once you add the .globl declaration and assemble the new source, nm so should show you an uppercase T instead. Uppercase indicates the label is externally visible.

As far as I can see from your question, you overwrite your object file that came from the assembler so by the C program. So you don't have the assembler routine any more.

You should probably write

Generate the so object file

 nasm s.asm -f elf -o s.o

Generate the test.o (your command created another so)

 gcc test.c -c 

Link the app

 gcc s.o test.o -o testapp 

(I chose testapp as output binary because test is often a very bad name for a program, it collides with the Unix command test )

It is better to declare the asm inline in c files. Here is an example from my own code:

bool KxMutex::tryLock_i()
{
#ifdef KX_MUTEX_ASM
   int oldLock;
#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
   asm volatile (
     "movl $1,%%eax\n\t"
     "xchg %%eax,%0\n\t"
     "movl %%eax,%1\n\t"
     : "=m" (mLock), "=m" (oldLock)
     :
     : "%eax", "memory"
   );
#elif defined(__GNUC__) && (defined(__ppc__))
   int newLock = 1;
   asm volatile (
     "\n1:\n\t"
     "lwarx  %0,0,%1\n\t"
     "cmpwi  0,%0,0\n\t"
     "bne-   2f\n\t"
     "stwcx. %2,0,%1\n\t"
     "bne-   1b\n\t"
     "isync\n"
     "2:\n\t"
     : "=&r" (oldLock)
     : "r" (&mLock), "r" (newLock)
     : "cr0", "memory"
  );
#endif
   return ( oldLock == 0 );
#else // !KX_MUTEX_ASM
   return ( pthread_mutex_trylock( (pthread_mutex_t*)this ) ? false : true );
#endif // !KX_MUTEX_ASM
}

There are many advantages:

  1. You don't have to manage the stack frame, return values etc yourself.
  2. The compiler can inline the function when necessary, since it controls the calling convention
  3. You can reference c language symbols directly in the .asm code
  4. It is easier to have different versions of ASM for different platforms controlled from the same c macros and definitions.
  5. All the c and c++ function modifiers work - extern, static, inline etc.
  6. The compiler can still do type checking on your function arguments, check that the function is called correctly etc.
  7. You can protect your variables with const as needed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM