【问题标题】:AT&T Assembly Syntax in C program (GCC compiler)?C 程序中的 AT&T 汇编语法(GCC 编译器)?
【发布时间】:2018-11-11 16:27:19
【问题描述】:

如果我在 Windows x86 上使用 GCC 编译器编译它,我有以下程序(AT&T 汇编语法)可以完美运行:

LC0:
    .ascii "Hello, world!\0"
.globl  _main
_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    call    ___main
    movl    $LC0, (%esp)
    call    _puts
    movl    $0, %eax
    leave
    ret

这个简单的程序可以在 C 程序中执行吗?我尝试了以下方法:

#include <stdlib.h>

int main()
{

    __asm__ ("LC0:\n\t"
             ".ascii 'Welcome Message\0'\n\t"
             "LC1:\n\t"
             ".ascii 'Hello\0'\n\t"
             "_main:\n\t"
             "LFB11:\n\t"
             "leal  4(%esp), %ecx\n\t"
             "andl  $-16, %esp\n\t"
             "pushl -4(%ecx)\n\t"
             "pushl %ebp\n\t"
             "movl  %esp, %ebp\n\t"
             "pushl %ecx\n\t"
             "subl  $20, %esp\n\t"
             "call  ___main\n\t"
             "movl  $1, 12(%esp)\n\t"
             "movl  $LC0, 8(%esp)\n\t"
             "movl  $LC1, 4(%esp)\n\t"
             "movl  $0, (%esp)\n\t"
             "call  _MessageBoxA@16\n\t"
             "subl  $16, %esp\n\t"
             "movl  $0, %eax\n\t"
             "movl  -4(%ebp), %ecx\n\t"
             "leave\n\t"
             "leal  -4(%ecx), %esp\n\t"
             "ret\n\t");


    return 0;

}

我得到一个错误:

错误:行尾有垃圾,第一个无法识别的字符是 `8'

【问题讨论】:

  • @Someprogrammerdude GCC 没有内联汇编程序。 GCC 对您的内联程序集进行文本替换并将其粘贴到自己的程序集输出中。也就是说,clang 确实有一个不理解某些结构的内联汇编程序。
  • 这不是minimal reproducible example,因为您的代码甚至不包含您的错误消息所抱怨的字符8。您究竟是如何在全局范围内对包含 __asm__ 语句的文件运行编译器的?为什么还要将 asm 放在全局范围而不是单独的 .s 文件中?
  • 嵌入的'\0' 可能会导致问题。您可能想尝试像"\\0" 一样逃避它。或者改用.asciiz 指令。
  • Junk at the end of the line 意味着有... junk 在行尾。检查行尾的隐藏或无意义的字符。
  • 为什么你还想做这样的事情?将某些程序集直接复制到 C 函数中的目的是什么?为什么不能将汇编文件保持原样并使用它而不是将代码包装在 C 函数中?

标签: c gcc assembly inline-assembly


【解决方案1】:

这很好用:

__asm__(
"LC0:\n"
"    .ascii \"Hello, world!\\0\"\n"
".globl  _main\n"
"_main:\n"
"    pushl   %ebp\n"
"    movl    %esp, %ebp\n"
"    andl    $-16, %esp\n"
"    subl    $16, %esp\n"
"    call    ___main\n"
"    movl    $LC0, (%esp)\n"
"    call    _puts\n"
"    movl    $0, %eax\n"
"    leave\n"
"    ret\n"
);

只需 C-string-literal-转义双引号字符串和 's/^/"/;s/$/\\n"/' 其他地方。

我的 gcc 的汇编器不接受单引号字符串文字

LC0:
    .ascii 'Hello, world!\0'
.globl  _main
_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $16, %esp
    call    ___main
    movl    $LC0, (%esp)
    call    _puts
    movl    $0, %eax
    leave
    ret

所以如果您通过__asm__ 提供它们,我不明白为什么它应该开始接受它们。

【讨论】:

  • 我尝试了第一个示例,收到错误 - “符号 `_main' 已定义”。它在您的计算机上对您有用吗?
  • @Lavonen 您在编译时添加了任何其他代码吗?比如,一个main函数的定义?因为那当然行不通。将asm 语句放在任何函数之外。
  • @Lavonen:您可能将其 inside 放在了 main 函数的 C 定义中,就像您的问题一样。这是不正确的,而不是 PSkocik 在做什么。将 asm 放在全局范围内,如果您想自己编写函数序言和 ret,请使用 __attribute__((naked))。从包含内联汇编的源代码中查看 C 编译器的汇编输出在调试内联汇编时很有用(尤其是在有约束的情况下,但在这种情况下也是如此)。
  • 顺便说一句,制作以零结尾的字符串的正常方法是使用.asciz aka .asciiz,而不是将\0 放在带引号的字符串中。
  • 现在它可以工作了,我把代码放在了一个函数中。不明白无论出于何种原因它必须在外面。感谢您的精彩回答,将投票!))
猜你喜欢
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-12
  • 1970-01-01
  • 2021-02-01
相关资源
最近更新 更多