我如何编译由GCC生成的汇编代码?

93
我正在测试一些汇编代码,有些东西让我感到困扰。
我编译这个:
#include <stdio.h>

int main(int argc, char** argv){
  printf("Hello World\n");
  return 0;
}

使用gcc file.c -S -o file.S可以生成一段漂亮的汇编代码:

    .cstring
LC0:
    .ascii "Hello World\0"
    .text
.globl _main
_main:
LFB3:
    pushq   %rbp
LCFI0:
    movq    %rsp, %rbp
LCFI1:
    subq    $16, %rsp
LCFI2:
    movl    %edi, -4(%rbp)
    movq    %rsi, -16(%rbp)
    leaq    LC0(%rip), %rdi
    call    _puts
    movl    $0, %eax
    leave
    ret
LFE3:
    .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
    .set L$set$0,LECIE1-LSCIE1
    .long L$set$0
LSCIE1:
    .long   0x0
    .byte   0x1
    .ascii "zR\0"
    .byte   0x1
    .byte   0x78
    .byte   0x10
    .byte   0x1
    .byte   0x10
    .byte   0xc
    .byte   0x7
    .byte   0x8
    .byte   0x90
    .byte   0x1
    .align 3
LECIE1:
.globl _main.eh
_main.eh:
LSFDE1:
    .set L$set$1,LEFDE1-LASFDE1
    .long L$set$1
LASFDE1:
    .long   LASFDE1-EH_frame1
    .quad   LFB3-.
    .set L$set$2,LFE3-LFB3
    .quad L$set$2
    .byte   0x0
    .byte   0x4
    .set L$set$3,LCFI0-LFB3
    .long L$set$3
    .byte   0xe
    .byte   0x10
    .byte   0x86
    .byte   0x2
    .byte   0x4
    .set L$set$4,LCFI1-LCFI0
    .long L$set$4
    .byte   0xd
    .byte   0x6
    .align 3
LEFDE1:
    .subsections_via_symbols

我的下一个问题是,我如何编译这个输出并让GCC为我完成?

7个回答

116

是的,你可以使用gcc编译汇编代码。像这样使用-c进行编译:

gcc -c file.S -o file.o

这将生成一个名为file.o的目标代码文件。 要调用链接器,请在上述命令之后执行以下操作:

gcc file.o -o file

50
你也可以只使用gcc file.S -o file来进行编译。 - Breno Leitão
1
"> as -o hello.o hello.s" 是什么意思?如 https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html 所示,似乎处理的顺序是预处理(*.i 文件)、编译(*.s 文件)、汇编(*.o 文件)和链接(*.exe 文件)。 - user1677716
1
@user1677716:是的,如果你给gcc -c一个.s文件,那就是它运行的内容。你可以使用gcc -v来查看它运行的命令,例如gcc -v -c foo.s或者gcc -v foo.s来汇编和链接。链接部分比只是ld foo.o更复杂;它必须与CRT启动代码和包括libc(-lc)在内的库进行链接。 - Peter Cordes

61

gcc可以使用汇编文件作为输入,并在需要时调用汇编器。然而存在一个微妙的问题:

  • 如果文件名以小写字母's'结尾(例如:.s),则gcc会调用汇编器。
  • 如果文件名以大写字母'S'结尾(例如:.S),则gcc会对源文件应用C预处理器(即识别诸如#if并替换宏等指令),然后在结果上调用汇编器。

因此,一般来说,您要像这样做:

gcc -S file.c -o file.s
gcc -c file.s

这看起来像是在工作,但我收到了一个错误信息:'Malformed Mach-o file'。 - Martin Kristiansen
我认为你必须使用.S前缀(大写),否则gcc会检测到另一种文件类型(例如,使用.asm失败)。 - Jean-François Fabre

13

您可以将汇编代码嵌入到普通的C程序中。这里有一个很好的介绍。使用适当的语法,您还可以告诉GCC您想要与在C中声明的变量交互。下面的程序指示gcc:

  • eax应为foo
  • ebx应为bar
  • 执行汇编代码后,eax中的值应存储在foo中

\n

int main(void)
{
        int foo = 10, bar = 15;
        __asm__ __volatile__("addl  %%ebx,%%eax"
                             :"=a"(foo)
                             :"a"(foo), "b"(bar)
                             );
        printf("foo+bar=%d\n", foo);
        return 0;
}

3
是的,gcc也可以编译汇编源代码。另外,你可以调用汇编器as。(gcc只是一个“驱动”程序,它使用启发式算法调用C编译器、C++编译器、汇编器、链接器等)

1
我该如何确定gcc将使用什么作为? - Martin Kristiansen
另外,我手头有英特尔的icc,它们使用哪种汇编语言? - Martin Kristiansen
6
请执行命令 gcc -v 并记录其操作。 - SK-logic

3

3

请注意,您不能使用ld将可执行文件链接起来(除非添加大量选项):您仍然需要使用gcc main.o -o main与CRT启动代码和-lc进行链接。 - Peter Cordes

-3
nasm -f bin -o 2_hello 2_hello.asm

2
这是一个非常简短的答案。您能否添加一些解释呢?也许您可以告诉我们参数的作用以及与其他答案相比您做了什么不同。 - GameDroids
GCC不会生成NASM语法,它会生成带有AT&T或.intel_syntax noprefix的GAS。没有任何GCC和NASM选项的组合可以让您使用GCC将C编译为汇编代码,然后再使用NASM进行汇编。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接