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