从 c 调用汇编函数

2024-10-28 08:37:00
admin
原创
324
摘要:问题描述:我正在尝试从 c 调用汇编函数,但一直出现错误。 .text .globl integrate .type integrate, @function integrate: push %ebp mov %esp, %ebp mov $0,%edi star...

问题描述:

我正在尝试从 c 调用汇编函数,但一直出现错误。

    .text
    .globl integrate
    .type integrate, @function
integrate:
    push %ebp
    mov %esp, %ebp
    mov $0,%edi
start_loop:                
    cmp %edi,1024           
    je loop_exit
    mov 8(%ebp),%eax          
    mov 12(%ebp),%ecx          
    sub %eax,%ecx              
    add %edi,%ecx
    incl %edi                
    jmp start_loop             
loop_exit:                 
    movl %ebp, %esp
    popl %ebp
    ret   

这是我的汇编函数,文件名为integrate.s。

#include <stdio.h>

extern int integrate(int from,int to);

void main()
{
    printf("%d",integrate(1,10));
}

这是我的 C 代码。

function.c:5:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
/tmp/cciR63og.o: In function `main':
function.c:(.text+0x19): undefined reference to `integrate'
collect2: ld returned 1 exit status

每当我尝试使用 gcc -Wall function.c -o function 编译代码时,它都会给出“未定义的对 integration 的引用”错误。我还尝试从 c 添加到 integration.s 文件的链接,例如

#include<(file path)/integrate.s>

但它没有很好地工作。顺便说一下,汇编代码的作用并不重要,现在我只是想成功地从 c 调用该函数。有人能帮我解决这个问题吗?


解决方案 1:

x86-64 Linux 示例

这里已经有一个答案显示了如何调用void func(void),但这里有一个x86-64 Linux 示例,它接受参数并具有返回值,这正是问题中所要求的。 (该问题和其他一些答案使用的是 32 位代码,它具有不同的调用约定)。

首先,让我们简化一下组装功能:

# Need to make it global so it can be accessed in another file with extern
.globl integrate

# Cannot hurt to define it as a function type, sometimes useful for dynamic linking, see comments in: https://stackoverflow.com/questions/65837016/how-to-call-a-function-in-an-external-assembly-file#comment116408928_65837016 
.type integrate, @function

integrate:
    # int integrate(int from /*EDI*/,  int to /*ESI*/)
    # INPUT:
    #   the first parameter `from` is contained in %edi, the int-sized low half of %rdi
    #   the second parameter `to`  is contained in %esi
    # OUTPUT:
    #   return is passed in %eax;  
    #      you can leave garbage in the high half of RAX if convenient

    lea  123(%rdi, %rsi), %ecx         # from + to + 123 just for example
    # (main work of function done)

    mov %ecx, %eax # it seems your return value is in %ecx
                   # but we need it in %eax for the return value to C
     # or just use EAX instead of ECX in the first place to avoid this instruction
    ret

这是使用System V调用约定,其中函数返回值被传回,并且函数接收的参数以相反的顺序rax传入rdi、、、、、,然后传入堆栈。(i386 和 x86-64 上 UNIX 和 Linux 系统调用(和用户空间函数)的调用约定是什么)。例如:rsi`rdxrcxr8`r9

long add_four_nums(int first, long second, short third, unsigned fourth);

使用此原型声明的函数将接收firstin %edisecondin %rsithirdin%dxfourthin %ecx。它将返回其resultin %rax

现在我们已经编写了汇编代码(尽管该函数主要是一个存根,用于展示如何接受参数和返回值),您可以像现在一样在 C 文件中使用该函数:

#include <stdio.h>
extern int integrate(int from,int to);
int main() {
    printf("%d
", integrate(1,10));
}

它可以与 gcc 编译并链接,然后运行,如下所示:

$ gcc -o combined -Wall main.c integrate.s   && ./combined

解决方案 2:

我发现代码存在以下问题:

  • 调用约定要求你必须保留edi

  • cmp %edi,1024用作1024地址,可能会出错。您需要cmp $1024,%edi与立即数进行比较

  • eax每次迭代时,您都会重新加载ecx参数,因此执行的计算不会产生任何效果

  • 你似乎没有输入任何合理的返回值eax(它将返回from传入的值)

即使“汇编代码的作用并不重要”,前两点仍然适用。

解决方案 3:

不确定您是否已解决这个问题,但这是我解决的方法。

编译时请确保添加两个文件:$gcc main.c print_msg.s -o main

要单独运行汇编程序文件:$as print_msg.s -o print_msg.o后跟$ld print_msg.o -e print -o print_msg。请注意,如果您只想从 C 文件运行它,则不需要这样做。

汇编文件:
print_msg.s

# A program to be called from a C program
# Declaring data that doesn't change
.section .data
    string: .ascii  "Hello from assembler
"
    length: .quad   . - string

# The actual code
.section .text
.global print
.type print, @function              #<-Important

print:
    mov     $0x1,%rax               # Move 1(write) into rax
    mov     $0x1,%rdi               # Move 1(fd stdOut) into rdi.
    mov     $string,%rsi            # Move the _location_ of the string into rsi
    mov     length,%rdx             # Move the _length_ of the string into rdx
    syscall                         # Call the kernel

    mov     %rax,%rdi               # Move the number of bytes written to rdi
    mov     $0x3c,%rax              # Move 60(sys_exit) into rax
    syscall                         # Call the kernel

然后是 C 文件:main.c

extern void print(void);

int main(void)
{
    print();
    return 0;
}

解决方案 4:

警告:'main' 的返回类型不是 'int'

意味着'main'的返回类型不是'int'...将其更改为int,然后:

int main()
{
}

另外,为了解决链接器错误,请按如下方式调用 GCC

gcc -o myprog main.c integrate.s

这应该可行。

解决方案 5:

第一个变化:

/* void main() */
int main(void)

main不能为 void,必须返回一个整数(通过错误)。为了C查看您的integrate函数,您必须在头文件或 C 文件中指定其函数签名,然后您可以执行以下操作:

as -o integrate.o integrate.s

然后,执行以下操作:

gcc -Wall -c c_program.c

最后,执行以下操作:

gcc c_program.o integrate.o -o integrate

然后尝试:

./integrate

或者

sudo chmod u+x ./integrate && ./integrate

注意:头文件看起来应该是这样的:

/* integrate.h */
#ifndef INTEGRATE
#define INTEGRATE
return_type integrate(ARGS, ...); /*if any ARGS are passed*/
#endif

并将其放在#include "integrate.h"C 文件的顶部。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用