【问题标题】:How to use asm function in C如何在 C 中使用 asm 函数
【发布时间】:2017-04-27 11:22:58
【问题描述】:

我在开发 hadoop 源代码的工作中遇到了问题。我需要在 asm 库中使用函数。给出了 API,例如: uint32_t func(uint32_t var1,const char var2,uint64_t var3)。 如何在 C 程序中使用此函数并获取返回值?我总是得到undefined reference to "a function name(which I want to use asm api)"。 是否有一些我必须在 C 或其他内容中添加的典型声明?

对于专业的 C 程序员来说,这似乎很容易,没有什么值得提问的。但我是一名Java程序员,对ASM和C真的很陌生,希望能高效得到答案。谢谢你。

【问题讨论】:

  • API是怎么给的?是否有包含函数原型的头文件?你包括了吗?是否将 asm 库添加到项目中以便链接?
  • "API给了?"如果您有一个头文件,请确保将其包含在您的 .c 文件中,并确保您的库已添加到项目中并链接到您的项目。也许这个帖子会对你有所帮助:stackoverflow.com/questions/24991944/linking-c-with-nasm
  • 您为什么操作系统和架构编程?可以给我们看看相关代码吗?
  • 你使用什么编译器?什么汇编程序?您在 C 和汇编程序之间进行接口的确切方式取决于这些事情......

标签: c assembly


【解决方案1】:

让我们以 gnu 为例,gcc 和语言本身告诉我们,如果我们将函数声明为静态,那么它对其他 .c 文件不可用。在 gnu 汇编器中,汇编语言是由汇编器定义的,而不是一些通用语言标准,标签是本地的,除非声明为全局的。

hello:
.globl there
there:

我们无法链接到 hello,但我们可以链接到那里。

然后您需要知道调用约定,您可以查找并阅读它和/或做实验来弄清楚它。即使您阅读它以确保您使用的编译器符合您正在阅读的编译器,您仍然应该进行实验,您使用的编译器将符合它使用的任何标准,而不是您希望它使用的标准,所以让你的 asm 匹配...

unsigned int fun ( unsigned int a, unsigned int b )
{
    return((a<<2)+b);
}

给予

00000000 <fun>:
   0:   e0810100    add r0, r1, r0, lsl #2
   4:   e12fff1e    bx  lr

这是 arm,在这种情况下,如果参数合适,则传入 r0,r1,r2,r3,如果有更多参数则进入堆栈。如果合适,返回值在 r0 中,有很多异常。您可以在函数中销毁 r0-r3 但必须保留 r4 (可能有一个例外)。所以在这种情况下,r0 向左移动 2 并添加到 r1,所以 r0 是 a,然后 r1 必须是 b,并且根据这个实验,返回值在 r0 中。

00000000 <fun>:
   0:   0f 5f           rla r15     
   2:   0f 5f           rla r15     
   4:   0f 5e           add r14,    r15 
   6:   30 41           ret 

使用另一个指令集 r15 似乎是 a 和 r14 b 并在 r15 中返回答案

00000000 <_fun>:
   0:   1166            mov r5, -(sp)
   2:   1185            mov sp, r5
   4:   1d40 0004       mov 4(r5), r0
   8:   0cc0            asl r0
   a:   0cc0            asl r0
   c:   6d40 0006       add 6(r5), r0
  10:   1585            mov (sp)+, r5
  12:   0087            rts pc

另一个指令集使用堆栈

我建议您对要从 C 中的 C 调用的 asm 函数进行原型设计,然后对其进行编译、反汇编并从那里构建您的 asm。实际组装它比尝试使用内联汇编要容易得多,这是一个高级主题并且非常依赖于编译器,如果你不使用内联汇编,你就有更好的机会工作。

例如,我会利用学到的知识来创造

.globl myfun
myfun:
   add r0,r1,r0, lsl #2
   bx lr

然后我可以将它组装起来,并将它与任何想用两个参数调用 myfun 的人联系起来。或者我可以使用这些知识对这两个参数做其他事情来创建返回值。

【讨论】:

  • 哇!将 asm 和 C 结合在一起真是个好建议。我会进一步考虑。您说内联汇编是一个高级主题并且依赖于编译器。你的意思是用C语言做asm原型可以避免编译器差异的问题吗?
  • 为了使您的内联程序集不与编译器生成的程序集发生冲突,特别是您想要使用的寄存器,或者更糟糕的是,如果您想将 C 中的变量与程序集连接起来,您必须学习该编译器的语法关于如何做到这一点,它不仅仅是汇编,它是其他编译器的东西,它们不是从未使用过但不常用,因此文档和/或那里这样做的人数较少。如果你想学习 asm,学习 asm,然后学习特定的编译器内容,同样的 C 学习 C 然后学习编译器特定的东西......或者......
【解决方案2】:

如果您需要从 Java 调用 C 或程序集,请使用 JNI 或其替代方法。要调用程序集,请创建一个小的 C 包装函数来模拟程序集应该做什么,然后编译它并使用您的 Java 程序进行调试(验证您可以传递参数、获取返回值)。

当它工作时,专注于从 C 调用实际的程序集。这真的取决于那个“asm 库”,它应该有文档说明如何从 C 调用它。

请注意,汇编库通常需要特定的 CPU 架构。例如,如果该库适用于 Intel 32 位,则无法从 Java VM 中为 64 位 ARM 调用它(至少,这并不容易)。

【讨论】:

  • 是的,我的目标程序集库是 Intel 的。我成功构建了它,我需要的功能可以在 xxx.so 文件中找到。就像你说的,我需要的只是一个 C 包装函数来连接 java 和程序集。 C 代码已准备就绪。但是,我确切地知道如何在 C 和程序集之间进行引用。我觉得它只需要在 C 代码中进行一些声明。你能给我一些线索吗?
  • 一个英特尔库应该带有一个体面的文档和一些示例。尝试找到它。通常他们应该有一些 C 包含文件,也就是“.h 文件”。
猜你喜欢
  • 1970-01-01
  • 2011-11-05
  • 2014-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多