【问题标题】:Segmentation fault (core dumped) when trying to call assembly functions from C尝试从 C 调用汇编函数时出现分段错误(核心转储)
【发布时间】:2019-06-23 06:32:11
【问题描述】:

运行此程序后,我在使用 Ubuntu 14.04 时遇到了一个错误“分段错误(核心转储)”,有人可以告诉我这是什么错误以及如何解决它吗?这是代码:

#include<stdlib.h>
#include<stdio.h>

typedef struct {
  char hex[17];
  char dezimal[21];
}Stu;

extern Stu* _structfunc(int n);
int main(int argc, char *argv[])
{
        Stu* a = _structfunc(123456);
        printf("%s,%s",a->hex,a->dezimal);
        free (a);
        return 0;
} 
LEN_HEX equ 16
LEN_DEZ equ 10
LEN_STRUCT equ LEN_HEX + 1 + LEN_DEZ + 1
SECTION .data
base10 dq 10
base16 dq 16
SECTION .text
global _structfunc
extern malloc
extern free
_structfunc:
        push rbp
        mov rbp,rsp
        push rbx ;save the previous value in rdi 
        push rdi ;s.o.
        mov rdi,LEN_STRUCT
        call malloc ;adress in rax
        mov rbx,rax
        mov rax,[rsp]
        mov rcx,LEN_HEX
hex:
        mov rdx,0
        div qword [base16]
        cmp rdx,10
        jae hex_charactor
        add rdx,0x30
        jmp hex_end
hex_charactor:
        add rdx,0x37
hex_end:
        mov [rbx+rcx-1],dl
        loop hex
        mov byte [rbx+LEN_HEX],0
        mov rax,[rsp]
        mov rcx, LEN_DEZ
dez:
        mov rdx,0
        div qword [base10]
        add rdx,0x30
dez_end:
        mov [rbx+LEN_HEX+1+rcx-1],dl
        loop dez
        mov byte [rbx+LEN_STRUCT-1],0
        add rsp,8
        pop rbx
        pop rbp
        ret

函数应该返回一个结构地址,包括十六进制形式的123456和十进制形式的123456

【问题讨论】:

  • 阅读undefined behaviorsegmentation faultAssembly HowToHow to debug small programs以及更多关于x86-64 ABI的信息。 StackOverflow 不是 debug-my-programdo-my-homework 网站
  • BTW Ubuntu 14真的已经过时了。考虑升级您的 Linux 发行版。当前的 Ubuntu 是18.04。另见norvig.com/21-days.html
  • div qword [base16] 是做什么的?该指令中的除数是多少?
  • @selbie:除数是.data 部分中的qword 16 (base16 dq 16)。 base16 是一个标签。建议使用label:,但在行首仅使用label 并不是语法错误。被除数是隐含的 RDX:RAX,OP 通过将 RDX 归零来正确地从 RAX 进行零扩展。这当然难以置信与 shift/AND 相比效率低下,因为 16 是 2 的幂。有关执行此操作的有效方法,请参阅 How to convert a number to hex?,包括标量和 SSE2,以及只有 2 的 AVX512VBMI 版本真正的指令 + 开销。
  • C 原型将 arg 声明为带符号的 32 位 int,但该函数实际上查看的是完整的 64 位值。在这种情况下,编译器可能会为您将 EDI 零扩展为 RDI(使用 mov edi, 123456),但这并不能保证,您应该将其声明为 func(uint64_t n),以便原型反映实现。

标签: c assembly x86-64


【解决方案1】:

分段错误意味着它试图访问一个无效的地址。

原因是它没有在 ret 之前加载带有返回值(来自 rbx)的 rax。

通常您会使用调试器来确定哪一行代码失败以及无效地址是什么,以便追踪无效地址的来源。

【讨论】:

  • 不幸的是,在这种情况下,它会在 printf 内部深处出现故障,因此通过阅读代码可能比通过调试更容易找到问题。
  • ty.i 之前我不知道返回值应该总是加载到 rax 中
猜你喜欢
  • 1970-01-01
  • 2020-05-30
  • 2022-01-04
  • 2013-08-14
  • 1970-01-01
  • 2019-08-11
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
相关资源
最近更新 更多