簡體   English   中英

C printf與匯編代碼混合時出現分段錯誤(核心已轉儲)

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

我嘗試了一些混合C代碼和x86匯編代碼的基本示例。 這是簡單的查找較小數字的示例。

這是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

這是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;
}

我在x64 Arch Linux上用gcc編譯它:

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

但是,當我啟動可執行文件p並插入2個數字並按Enter時,我得到:

Segmentation fault (core dumped)

我研究了所有以前類似的問題,並且嘗試了幾次嘗試,但是每次遇到相同的錯誤時,我都會嘗試。 我也嘗試使用gdb調試它,並且我看到Assembly函數min返回正確的結果,但是無論如何它總是卡在C printf函數上。

我試圖不從匯編文件中導入字符串out_format ,而是直接在C文件中定義它(我將其定義為簡單的char數組,還使用mallocfree函數將其定義為char指針),但沒有幫助。

否則,如果我使用一些整數而不是匯編函數min的結果來初始化變量r ,則程序不會給出此類錯誤。 但這對我沒有任何意義,因為我已經用gdb檢查了它,並且Assembly函數正確地將變量r正確地初始化為正確的較小數字。

拜托,有人可以幫我嗎?

提前致謝

如果min()運作良好,請檢查out_format。

以下代碼有效。

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

完整的代碼

#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;
}

最后,我只想保留有效的代碼。

文件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

文件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;
}

感謝大家的幫助。

asm使用ret 8在返回時從堆棧中彈出args。

標准的32位x86 Linux調用約定( i386 System V ABI )是caller-pops。 函數僅使用ret返回 ,如果/需要,調用者可以清理堆棧。 (例如,使用mov存儲在另一個call之前編寫新的arg,而不是調整esp並再次使用push 。)

正如OP的自我回答指出的那樣,您可以改為將min聲明為

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

因此,編譯器生成的代碼將與調用約定上的asm一致。 該調用約定有時在Windows上使用。

如果與調試器一起進行單步調試,就會發現這一點(如果您知道要查找的內容)。 始終使用調試器找出您的代碼段在哪里,然后查看寄存器並向后工作以找出原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM