GCC 和 mingw 之间 .s 汇编的差异:如何在 Windows 上编译 QBE 输出?

问题描述 投票:0回答:1

我想使用我为 Windows 编译的 QBE(一个简单的编译器后端)。

为了尝试一下,我想编译示例文件

hello.ssa

function w $add(w %a, w %b) {              # Define a function add
@start
    %c =w add %a, %b                   # Adds the 2 arguments
    ret %c                             # Return the result
}
export function w $main() {                # Main function
@start
    %r =w call $add(w 1, w 1)          # Call add(1, 1)
    call $printf(l $fmt, ..., w %r)    # Show the result
    ret 0
}
data $fmt = { b "One and one make %d!\n", b 0 }

我用QBE编译的:

> qbe.exe -o out.s hello.ssa

这给了我以下

out.s
文件:

.text
add:
    pushq %rbp
    movq %rsp, %rbp
    movl %edi, %eax
    addl %esi, %eax
    leave
    ret
.type add, @function
.size add, .-add
/* end function add */

.text
.globl main
main:
    pushq %rbp
    movq %rsp, %rbp
    movl $1, %esi
    movl $1, %edi
    callq add
    movl %eax, %esi
    leaq fmt(%rip), %rdi
    movl $0, %eax
    callq printf
    movl $0, %eax
    leave
    ret
.type main, @function
.size main, .-main
/* end function main */

.data
.balign 8
fmt:
    .ascii "One and one make %d!\n"
    .byte 0
/* end data */

.section .note.GNU-stack,"",@progbits

然后我想用 MinGW 创建一个可执行文件:

> gcc -o hello.exe out.s
out.s: Assembler messages:
out.s:9: Warning: .type pseudo-op used outside of .def/.endef: ignored.
out.s:9: Error: junk at end of line, first unrecognized character is `a'
out.s:10: Warning: .size pseudo-op used outside of .def/.endef: ignored.
out.s:10: Error: junk at end of line, first unrecognized character is `a'
out.s:28: Warning: .type pseudo-op used outside of .def/.endef: ignored.
out.s:28: Error: junk at end of line, first unrecognized character is `m'
out.s:29: Warning: .size pseudo-op used outside of .def/.endef: ignored.
out.s:29: Error: junk at end of line, first unrecognized character is `m'
out.s:39: Error: junk at end of line, first unrecognized character is `-'

这是我运行示例时得到的输出。它在 wsl 上使用 GCC 编译得很好:

wsl gcc -o hello out.s

但是 MinGW gcc 编译器似乎不理解汇编。

我注意到两个编译器之间简单的 C Hello, World 的默认 .s 输出也不同。例如:

gcc -S hello.c

根据使用的平台提供不同的 .s 文件。

那么我可以使用什么编译器/编译器标志/汇编器从 Windows 上的 qbe 生成的 out.s 文件中获取机器代码?

其次,我认为QBE目前仅支持system-V ABI,所以我需要链接system-V存根函数而不是CRT库函数是否正确,或者mingw CRT是否已经使用system-V ABI?

assembly gcc mingw abi
1个回答
0
投票

我通过修补 QBE 使其编译,使其不在其汇编输出中发出 .size 和 .type。所以当我编译时:

function w $add(w %a, w %b) {             
@start
    %c =w add %a, %b                   
    ret %c                             
}
export function w $main() {                
@start
    %r =w call $add(w 1, w 1)          
    call $sysv_printf(l $fmt, ..., w %r) # Calling my wrapper
    ret 0
}
data $fmt = { b "One and one make %d!\n", b 0 }

通过 QBE 我得到:

.text
add:
    pushq %rbp
    movq %rsp, %rbp
    movl %edi, %eax
    addl %esi, %eax
    leave
    ret
/* end function add */

.text
.globl main
main:
    pushq %rbp
    movq %rsp, %rbp
    movl $1, %esi
    movl $1, %edi
    callq add
    movl %eax, %esi
    leaq fmt(%rip), %rdi
    movl $0, %eax
    callq sysv_printf
    movl $0, %eax
    leave
    ret
/* end function main */

.data
.balign 8
fmt:
    .ascii "One and one make %d!\n"
    .byte 0
/* end data */

我创建了一个 C 包装器:

#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

int __attribute__((sysv_abi)) sysv_printf( const char *restrict fmt, ... ) {
    printf("Called with %s", fmt);
    assert(strcmp(fmt, "One and one make %d!\n") == 0);
    va_list ap;
    va_start(ap, fmt);
    int smth = va_arg(ap, int);
    printf("%d\n", smth);
    va_end(ap);
    printf("Finish");
}

所以如果我在批处理文件中运行这些步骤

call qbe -o out.s hello.ssa
call gcc -c out.s
call gcc -c stub.c
call gcc -S -fno-asynchronous-unwind-tables stub.c
call gcc -o main.exe stub.o out.o

我得到了一个可执行的 main.exe。

但是,当我运行它时,某些东西不适用于可变参数:

Called with One and one make %d!

格式字符串有效,但整数似乎未正确传递。 如果我检查返回值:

> echo %errorlevel%
-1073741819

这可能是由于我的程序导致分段错误。

© www.soinside.com 2019 - 2024. All rights reserved.