在Linux vs Mac上将C汇编为ARM64时的不同说明

发布于 2025-02-07 21:02:56 字数 2752 浏览 2 评论 0原文

如果我将AC文件编译到ARM64组件中,我会获得不同的说明(不仅是不同的语法和指令 - 例如.cfi_def_cfa vs .cfi_def_cfa_offset)苹果。如果ISA是相同的,为什么这是如此?我知道会有不同的目标二进制格式(ELF/MACH-O),但是我期望将相同的说明汇编为不同的对象。这是因为Apple使用Apple Clang可能与AARCH64 GCC工具链内部的处理情况不同?

有什么方法可以使用相同的说明执行?

输入文件(fib.c):

int fib(int n)
{
    if (n <= 1)
        return 1;

    return fib(n - 1) + fib(n - 2);
}

Mac(在Mac mini上使用GCC -S FIB.C -O FIB.S):

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 11, 0 sdk_version 12, 1
    .globl  _fib                            ; -- Begin function fib
    .p2align    2
_fib:                                   ; @fib
    .cfi_startproc
; %bb.0:
    sub sp, sp, #32                     ; =32
    stp x29, x30, [sp, #16]             ; 16-byte Folded Spill
    add x29, sp, #16                    ; =16
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    str w0, [sp, #8]
    ldr w8, [sp, #8]
    subs    w8, w8, #1                      ; =1
    b.gt    LBB0_2
; %bb.1:
    mov w8, #1
    stur    w8, [x29, #-4]
    b   LBB0_3
LBB0_2:
    ldr w8, [sp, #8]
    subs    w0, w8, #1                      ; =1
    bl  _fib
    str w0, [sp, #4]                    ; 4-byte Folded Spill
    ldr w8, [sp, #8]
    subs    w0, w8, #2                      ; =2
    bl  _fib
    mov x8, x0
    ldr w0, [sp, #4]                    ; 4-byte Folded Reload
    add w8, w0, w8
    stur    w8, [x29, #-4]
LBB0_3:
    ldur    w0, [x29, #-4]
    ldp x29, x30, [sp, #16]             ; 16-byte Folded Reload
    add sp, sp, #32                     ; =32
    ret
    .cfi_endproc
                                        ; -- End function
.subsections_via_symbols

Linux(在Ubuntu上使用aarch64 -linux -gnu汇总-gcc -s fib.c -o fib.s):

    .arch armv8-a
    .file   "fib.c"
    .text
    .align  2
    .global fib
    .type   fib, %function
fib:
.LFB0:
    .cfi_startproc
    stp x29, x30, [sp, -48]!
    .cfi_def_cfa_offset 48
    .cfi_offset 29, -48
    .cfi_offset 30, -40
    mov x29, sp
    str x19, [sp, 16]
    .cfi_offset 19, -32
    str w0, [sp, 44]
    ldr w0, [sp, 44]
    cmp w0, 1
    bgt .L2
    mov w0, 1
    b   .L3
.L2:
    ldr w0, [sp, 44]
    sub w0, w0, #1
    bl  fib
    mov w19, w0
    ldr w0, [sp, 44]
    sub w0, w0, #1
    bl  fib
    add w0, w19, w0
.L3:
    ldr x19, [sp, 16]
    ldp x29, x30, [sp], 48
    .cfi_restore 30
    .cfi_restore 29
    .cfi_restore 19
    .cfi_def_cfa_offset 0
    ret
    .cfi_endproc
.LFE0:
    .size   fib, .-fib
    .ident  "GCC: (Ubuntu 11.2.0-17ubuntu1) 11.2.0"
    .section    .note.GNU-stack,"",@progbits

If I compile a c file into ARM64 assembly I get different instructions (not only a different syntax and directives - eg .cfi_def_cfa vs .cfi_def_cfa_offset) depending on whether I compile on linux or mac. Why is this if the ISA is the same? I know there will be different target binary formats (ELF/Mach-O), but I was expecting identical instructions that would then be compiled into different objects. Is this because apple use apple clang which may process things differently from the internals of the aarch64 gcc toolchain?

Is there any way to enforce using the same instructions?

Input file (fib.c):

int fib(int n)
{
    if (n <= 1)
        return 1;

    return fib(n - 1) + fib(n - 2);
}

Mac (compiled on a mac mini with gcc -S fib.c -o fib.s):

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 11, 0 sdk_version 12, 1
    .globl  _fib                            ; -- Begin function fib
    .p2align    2
_fib:                                   ; @fib
    .cfi_startproc
; %bb.0:
    sub sp, sp, #32                     ; =32
    stp x29, x30, [sp, #16]             ; 16-byte Folded Spill
    add x29, sp, #16                    ; =16
    .cfi_def_cfa w29, 16
    .cfi_offset w30, -8
    .cfi_offset w29, -16
    str w0, [sp, #8]
    ldr w8, [sp, #8]
    subs    w8, w8, #1                      ; =1
    b.gt    LBB0_2
; %bb.1:
    mov w8, #1
    stur    w8, [x29, #-4]
    b   LBB0_3
LBB0_2:
    ldr w8, [sp, #8]
    subs    w0, w8, #1                      ; =1
    bl  _fib
    str w0, [sp, #4]                    ; 4-byte Folded Spill
    ldr w8, [sp, #8]
    subs    w0, w8, #2                      ; =2
    bl  _fib
    mov x8, x0
    ldr w0, [sp, #4]                    ; 4-byte Folded Reload
    add w8, w0, w8
    stur    w8, [x29, #-4]
LBB0_3:
    ldur    w0, [x29, #-4]
    ldp x29, x30, [sp, #16]             ; 16-byte Folded Reload
    add sp, sp, #32                     ; =32
    ret
    .cfi_endproc
                                        ; -- End function
.subsections_via_symbols

Linux (compiled on ubuntu with aarch64-linux-gnu-gcc -S fib.c -o fib.s):

    .arch armv8-a
    .file   "fib.c"
    .text
    .align  2
    .global fib
    .type   fib, %function
fib:
.LFB0:
    .cfi_startproc
    stp x29, x30, [sp, -48]!
    .cfi_def_cfa_offset 48
    .cfi_offset 29, -48
    .cfi_offset 30, -40
    mov x29, sp
    str x19, [sp, 16]
    .cfi_offset 19, -32
    str w0, [sp, 44]
    ldr w0, [sp, 44]
    cmp w0, 1
    bgt .L2
    mov w0, 1
    b   .L3
.L2:
    ldr w0, [sp, 44]
    sub w0, w0, #1
    bl  fib
    mov w19, w0
    ldr w0, [sp, 44]
    sub w0, w0, #1
    bl  fib
    add w0, w19, w0
.L3:
    ldr x19, [sp, 16]
    ldp x29, x30, [sp], 48
    .cfi_restore 30
    .cfi_restore 29
    .cfi_restore 19
    .cfi_def_cfa_offset 0
    ret
    .cfi_endproc
.LFE0:
    .size   fib, .-fib
    .ident  "GCC: (Ubuntu 11.2.0-17ubuntu1) 11.2.0"
    .section    .note.GNU-stack,"",@progbits

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

℉服软 2025-02-14 21:02:57

Mac上的GCC实际上是clang ,除非您安装了实际的GCC软件包。

(他们这样做是因为某些MakeFiles使用CC = GCC而不是CC = CC,并且它确实接受了几乎所有相同的选项。使用gcc -v -v 找出答案

  • 代码
  • 真正的GCC只是整个编译单元中的自动标签。

两个完全不同的编译器使不同优化的ASM 毫不奇怪。他们有不同的内部设备和转换,以从C来源制造ASM,例如Clang通过LLVM-IR,GCC穿过Gimple和RTL。

通过启用优化,对于足够简单的代码,他们倾向于同意是否只有一个好选择(除寄存器号码之外),但是一旦事情变得足够复杂,可以变得不乏味(例如优化迭代中的双重恢复功能),就会有空间每个人都做出不同的选择。

同一编译器的不同版本 /选项也是如此。

gcc on a Mac is actually clang, unless you install an actual GCC package.

(They do this because some Makefiles use CC=gcc instead of CC=cc, and it does accept almost all the same options. Use gcc -v to find out.)

Or we can tell from looking at the asm output:

  • The LBB0_3 label naming is indicative of LLVM, numbering by function and then basic-block within function.
  • True GCC just auto-numbers labels throughout the compilation unit.

It's not surprising that two totally different compilers make different un-optimized asm. They have different internals and transformations they go through to make asm from C source, e.g. clang going through LLVM-IR, GCC going through GIMPLE and RTL.

With optimization enabled, for simple enough code they tend to agree if there's only one good choice (other than register numbers), but once things get complex enough to be non-trivial (like optimizing a doubly-recursive function into iterative) there's room for each one to make different choices.

Same is true across different versions / options of the same compiler, too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文