assembly - 为什么编译器使用帧指针和链接寄存器?

assembly - 为什么编译器使用帧指针和链接寄存器?

我试图了解 GNU 如何解释几件事,所以我的第一个例子非常简单:声明一个整数并打印它。如果没有调用优化,汇编代码如下:

.arch armv8-a

.file "ex1.c"

.text

.section .rodata

.align 3 .LC0:

.string "%i\n"

.text

.align 2

.global main

.type main, %function main: .LFB0:

.cfi_startproc

stp x29, x30, [sp, -32]!

.cfi_def_cfa_offset 32

.cfi_offset 29, -32

.cfi_offset 30, -24

mov x29, sp

str w0, [sp, 28]

mov w0, 328

str w0, [sp, 28]

ldr w1, [sp, 28]

adrp x0, .LC0

add x0, x0, :lo12:.LC0

bl printf

nop

ldp x29, x30, [sp], 32

.cfi_restore 30

.cfi_restore 29

.cfi_def_cfa_offset 0

ret

.cfi_endproc .LFE0:

.size main, .-main

.ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"

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

如果编译优化(-O3),汇编代码更简洁:

.arch armv8-a

.file "ex1.c"

.text

.section .rodata.str1.8,"aMS",@progbits,1

.align 3 .LC0:

.string "%i\n"

.section .text.startup,"ax",@progbits

.align 2

.p2align 3,,7

.global main

.type main, %function main: .LFB23:

.cfi_startproc

adrp x1, .LC0

mov w2, 328

add x1, x1, :lo12:.LC0

mov w0, 1

b __printf_chk

.cfi_endproc .LFE23:

.size main, .-main

.ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"

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

除了 p2align 3,,7 之外,大多数东西都相对简单,我在阅读 sourceware 上的描述后仍在弄清楚。但是,我的主要问题是别的。为什么未优化版本使用帧指针和链接寄存器以及 CFA?它试图完成什么?有人可能想知道为什么我在乎,选择优化版本。原因是 Fortran 代码的优化版本通过使用帧指针和链接寄存器恢复到类似于未优化的 C 版本。

Fortran 代码很简单:

program integer_printing

integer (kind=4) a

a=328

write (*,*) a

end

和优化的汇编代码读取

.arch armv8-a

.file "exa1F.f90"

.text

.section .rodata.str1.8,"aMS",@progbits,1

.align 3

.LC0:

.string "exa1F.f90"

.text

.align 2

.p2align 3,,7

.type MAIN__, %function

MAIN__:

.LFB0:

.cfi_startproc

sub sp, sp, #576

.cfi_def_cfa_offset 576

adrp x0, .LC1

adrp x1, .LC0

add x1, x1, :lo12:.LC0

mov w3, 328

mov w2, 5

stp x29, x30, [sp]

.cfi_offset 29, -576

.cfi_offset 30, -568

mov x29, sp

ldr d0, [x0, #:lo12:.LC1]

str x19, [sp, 16]

.cfi_offset 19, -560

add x19, sp, 48

mov x0, x19

str w3, [sp, 44]

str d0, [sp, 48]

str x1, [sp, 56]

str w2, [sp, 64]

bl _gfortran_st_write

add x1, sp, 44

mov w2, 4

mov x0, x19

bl _gfortran_transfer_integer_write

mov x0, x19

bl _gfortran_st_write_done

ldp x29, x30, [sp]

ldr x19, [sp, 16]

add sp, sp, 576

.cfi_restore 29

.cfi_restore 30

.cfi_restore 19

.cfi_def_cfa_offset 0

ret

.cfi_endproc

.LFE0:

.size MAIN__, .-MAIN__

.section .text.startup,"ax",@progbits

.align 2

.p2align 3,,7

.global main

.type main, %function

main:

.LFB1:

.cfi_startproc

stp x29, x30, [sp, -16]!

.cfi_def_cfa_offset 16

.cfi_offset 29, -16

.cfi_offset 30, -8

mov x29, sp

bl _gfortran_set_args

adrp x1, .LANCHOR0

add x1, x1, :lo12:.LANCHOR0

mov w0, 7

bl _gfortran_set_options

bl MAIN__

mov w0, 0

ldp x29, x30, [sp], 16

.cfi_restore 30

.cfi_restore 29

.cfi_def_cfa_offset 0

ret

.cfi_endproc

.LFE1:

.size main, .-main

.section .rodata.cst8,"aM",@progbits,8

.align 3

.LC1:

.word 128

.word 6

.section .rodata

.align 3

.set .LANCHOR0,. + 0

.type options.1.2778, %object

.size options.1.2778, 28

options.1.2778:

.word 2116

.word 4095

.word 0

.word 1

.word 1

.word 0

.word 31

.ident "GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"

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

💎 相关推荐

作者:一棵绿树
英国365bet日博

作者:一棵绿树

📅 07-30 👁️ 5762
海外旅行,如何找个“良心导游”?丨HOW TO
365bet体育在线注册

海外旅行,如何找个“良心导游”?丨HOW TO

📅 07-12 👁️ 3846
2025年小游戏十大网站排行榜
365bet体育在线注册

2025年小游戏十大网站排行榜

📅 08-18 👁️ 6984