简体   繁体   English

C printf与汇编代码混合时出现分段错误(核心已转储)

[英]C printf Segmentation fault (core dumped) while mixing with Assembly code

I tried some basic example of mixing C code and x86 Assembly code. 我尝试了一些混合C代码和x86汇编代码的基本示例。 It is simple Find smaller number example. 这是简单的查找较小数字的示例。

Here is Assembly code in bs file (I have to use intel syntax with no prefix and i386 architecture): 这是bs文件中的汇编代码(我必须使用无前缀和i386体系结构的intel语法):

.intel_syntax noprefix
.arch i386

.data
    .globl out_format
    out_format:
        .asciz "min(%i, %i) = %i\n"

.text
    .globl min
    .type min, @function
    min:
        enter 0, 0
        mov ebx, [ebp + 8]
        cmp ebx, [ebp + 12]
        jle 1f
        mov eax, [ebp] + 12
        jmp 2f
        1:
            mov eax, ebx
        2:
            leave
        ret 8

.end

Here is the C code in ac file: 这是ac文件中的C代码:

#include<stdio.h>

extern char out_format;

extern int min(int x, int y);

int main() {
    int x1, x2, r;
    scanf("%i%i", &x1, &x2);
    r = min(x1, x2);
    printf(&out_format, x1, x2, r);

    return 0;
}

I compile it with gcc on x64 Arch Linux: 我在x64 Arch Linux上用gcc编译它:

gcc -m32 -Wall -Werror -g -o p b.s a.c

But when I start the executable file p, and insert 2 numbers and hit enter I get: 但是,当我启动可执行文件p并插入2个数字并按Enter时,我得到:

Segmentation fault (core dumped)

I researched all previous similar questions, and I tried several things but every time I get the same error. 我研究了所有以前类似的问题,并且尝试了几次尝试,但是每次遇到相同的错误时,我都会尝试。 I also tried to debug it with gdb, and I see that Assembly function min returns the right result, but somehow it always stuck on C printf function. 我也尝试使用gdb调试它,并且我看到Assembly函数min返回正确的结果,但是无论如何它总是卡在C printf函数上。

I tried to not import string out_format from Assembly file, and define it directly in C file (I defined it as simple array of chars, and also as char pointer using malloc and free functions) but it didn't help. 我试图不从汇编文件中导入字符串out_format ,而是直接在C文件中定义它(我将其定义为简单的char数组,还使用mallocfree函数将其定义为char指针),但没有帮助。

Otherwise the program doesn't give such error if I intialize variable r with some integer instead with result of Assembly function min . 否则,如果我使用一些整数而不是汇编函数min的结果来初始化变量r ,则程序不会给出此类错误。 But it doesn't have any sense to me as I already checked it with gdb and the Assembly function correctly intialize the variable r with correct smaller number. 但这对我没有任何意义,因为我已经用gdb检查了它,并且Assembly函数正确地将变量r正确地初始化为正确的较小数字。

Please, can anyone help me with this? 拜托,有人可以帮我吗?

Thanks in advance 提前致谢

if min() works good, check out_format. 如果min()运作良好,请检查out_format。

following code works. 以下代码有效。

printf("%d %d %d\n", x1, x2, r);

full code 完整的代码

#include<stdio.h>

int min(int x, int y)
{
    if (x<y) return x;
    return y;
}

int main() {
    int x1, x2, r;
    scanf("%i%i", &x1, &x2);
    r = min(x1, x2);
    printf("%d %d %d\n", x1, x2, r);
    return 0;
}

At the end I just want to leave the code that works. 最后,我只想保留有效的代码。

File bs: 文件bs:

.intel_syntax noprefix
.arch i386

.data
    .globl out_format
    out_format:
        .asciz "min(%i, %i) = %i\n"

.text
    .globl min
    .type min, @function
    min:
        enter 0, 0
        push ebx
        mov ebx, [ebp + 8]
        cmp ebx, [ebp + 12]
        jle 1f
        mov eax, [ebp] + 12
        jmp 2f
        1:
            mov eax, ebx
        2:
            pop ebx
            leave
        ret 8

.end

File ac: 文件ac:

#include<stdio.h>

extern char out_format;

extern int __attribute__((stdcall)) min(int x, int y);

int main() {
    int x1, x2, r;
    scanf("%i%i", &x1, &x2);
    r = min(x1, x2);
    printf(&out_format, x1, x2, r);

    return 0;
}

Thanks everyone for their help. 感谢大家的帮助。

The asm uses ret 8 to pop the args from the stack as it returns. asm使用ret 8在返回时从堆栈中弹出args。

The standard 32-bit x86 Linux calling convention ( i386 System V ABI ) is caller-pops. 标准的32位x86 Linux调用约定( i386 System V ABI )是caller-pops。 Functions just use ret to return and the caller can clean up the stack if / when it wants. 函数仅使用ret返回 ,如果/需要,调用者可以清理堆栈。 (eg use mov stores to write new args before another call instead of adjusting esp and using push again.) (例如,使用mov存储在另一个call之前编写新的arg,而不是调整esp并再次使用push 。)

As the OP's self answer points you, you could instead declare min as 正如OP的自我回答指出的那样,您可以改为将min声明为

extern int __attribute__((stdcall)) min(int x, int y);

so the compiler-generated code will agree with the asm on the calling convention. 因此,编译器生成的代码将与调用约定上的asm一致。 This calling convention is sometimes used on Windows. 该调用约定有时在Windows上使用。

Single-stepping with a debugger would have revealed this (if you knew what to look for). 如果与调试器一起进行单步调试,就会发现这一点(如果您知道要查找的内容)。 Always use a debugger to figure out where your code segfaults, then look at registers and work backwards to find out why. 始终使用调试器找出您的代码段在哪里,然后查看寄存器并向后工作以找出原因。

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

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