简体   繁体   English

从 C 源代码调用汇编例程

[英]Calling assembly routines from C source code

I have this simple C source code :我有这个简单的 C 源代码:

#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 :我有这个 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

now , i compiled the .asm using :现在,我编译了 .asm 使用:

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

and compiled and linked the .c file using :并使用以下命令编译和链接 .c 文件:

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我正在使用 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. [已解决]:我用 nm 检查了 test.o 文件,它希望找到符号“Sum”而不是“_Sum”,因此更改解决了问题。

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:此外,在 C 中正确声明例程。这不是链接错误的原因,但可能会导致其他问题:

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.) (这将可执行文件命名为“test”,您可能必须使用“./test”来执行它,以将目录中的“test”与“test”命令区分开来。您可能更愿意选择其他名称。)

For educational purposes: If you have the nm tool on your system, execute the command nm so .出于教育目的:如果您的系统上有nm工具,请执行命令nm so It may show you something like:它可能会显示如下内容:

00000000 t _Sum

The t means that _Sum is a local label in the code section. t表示_Sum是代码部分中的本地标签。 (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. (代码部分也称为文本部分,因此称为 t。)一旦您添加了.globl声明并组装了新的源代码, nm so应该向您显示一个大写的T 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被 C 程序覆盖。 So you don't have the assembler routine any more.所以你不再有汇编程序了。

You should probably write你应该写

Generate the so object file生成so对象文件

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

Generate the test.o (your command created another so)生成test.o (您的命令创建了另一个 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 ) (我选择 testapp 作为输出二进制文件,因为test通常是一个非常糟糕的程序名称,它与 Unix 命令test冲突)

It is better to declare the asm inline in c files.最好在 c 文件中声明 asm inline。 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可以直接在.asm代码中引用c语言符号
  4. It is easier to have different versions of ASM for different platforms controlled from the same c macros and definitions.从相同的 c 宏和定义控制不同平台的不同版本的 ASM 更容易。
  5. All the c and c++ function modifiers work - extern, static, inline etc.所有 c 和 c++ 函数修饰符都有效 - extern、static、inline 等。
  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.您可以根据需要使用 const 保护您的变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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