从C源代码调用程序集例程

我有这个简单的C源代码:

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

我有这个s.asm定义函数_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 

现在,我使用以下方法编译.asm:

 nasm s.asm -f elf -o so 

并使用以下方法编译和链接.c文件:

 gcc so test.o -o testapp 

这是结果:

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

那么问题是什么?

我正在使用Ubuntu-Linux

任何帮助将不胜感激,谢谢

[求助]:我用nm检查了test.o文件,它希望找到符号’Sum’而不是’_Sum’,所以改变它解决了问题。

据我所知,你可以通过C程序覆盖来自汇编程序的目标文件。 所以你不再拥有汇编程序了。

你可能应该写

生成so对象文件

  nasm s.asm -f elf -o so 

生成test.o (你的命令创建了另一个)

  gcc test.c -c 

链接应用程序

  gcc so test.o -o testapp 

(我选择testapp作为输出二进制文件,因为test通常是程序的一个非常糟糕的名称,它与Unix命令test冲突)

在典型的汇编程序中,标签默认为本地标签。 要告诉汇编程序使它们对外部例程可见,您必须添加一个声明,例如:

 .globl _Sum 

另外,在C中正确声明例程。这不是导致链接错误的原因,但可能导致其他问题:

 extern int Sum(int, int); 

为了完整起见,感谢评论者:不要覆盖您的目标文件。 您可以组装,编译和链接:

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

(这命名可执行文件“test”,您可能必须使用“./test”执行它以区分目录中的“test”和“test”命令。您可能更乐意选择其他名称。)

出于教育目的:如果您的系统上有nm工具,请执行命令nm so 。 它可能会显示如下:

 00000000 t _Sum 

t表示_Sum是代码部分中的本地标签。 (代码部分也称为文本部分,因此是t。)一旦你添加.globl声明并组装新的源, nm so应该显示一个大写的T 大写表示标签在外部可见。

最好在c文件中声明asm内联。 这是我自己的代码中的一个例子:

 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 } 

有许多优点:

  1. 您不必自己管理堆栈帧,返回值等。
  2. 编译器可以在必要时内联函数,因为它控制调用约定
  3. 您可以直接在.asm代码中引用c语言符号
  4. 对于由相同的c宏和定义控制的不同平台,更容易使用不同版本的ASM。
  5. 所有的c和c ++函数修饰符都可以工作 – extern,static,inline等。
  6. 编译器仍然可以对函数参数进行类型检查,检查函数是否正确调用等。
  7. 您可以根据需要使用const保护变量。