我试图了解 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