最新 gcc 的各种组合似乎存在一个微妙的问题,无论是有意的还是无意的。 Archlinux 上最新内核 4.15.8 上的 7.3 版。无论出于何种原因,为main() 生成的代码都省略了对func() 的调用。例如
$ gcc -S -masm=intel -o infunc2.asm infunc2.c
生成的程序集是:
$ cat infunc2.asm
.file "infunc2.c"
.intel_syntax noprefix
.text
.comm arr,40,32
.section .rodata
.LC0:
.string "In func"
.text
.globl func
.type func, @function
func:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
lea rdi, .LC0[rip]
call puts@PLT
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size func, .-func
.section .rodata
.LC1:
.string "In main"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
lea rdi, .LC1[rip]
call puts@PLT
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (GNU) 7.3.0"
.section .note.GNU-stack,"",@progbits
请注意,对func() 的调用在上面标记为.LFB0:。 main: 的过程根本不调用func 或.LFB0:,尽管它存在,尽管"In func" 字符串存在于.LC0: 中。我怀疑这不是预期的行为。
比如简单编译不优化-O0函数不被调用,例如:
$ gcc -g -O0 -o bin/if2 infunc2.c
$ ./bin/if2
In main
更改代码以存储arr[func()] 的地址确实会强制调用func(),例如
#include <stdio.h>
int arr[10];
int func()
{
printf ("In func\n");
return 0;
}
int main (void)
{
int *p = &arr[func()];
if (p)
printf("In main\n");
return 0;
}
然后
$ gcc -Wall -Wextra -pedantic -std=gnu11 -Ofast -o bin/infunc infunc.c
$ ./bin/infunc
In func
In main
并且生成的程序集支持不同的行为:
$ gcc -S -masm=intel -o infunc.asm infunc.c
$ cat infunc.asm
.file "infunc.c"
.intel_syntax noprefix
.text
.comm arr,40,32
.section .rodata
.LC0:
.string "In func"
.text
.globl func
.type func, @function
func:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
lea rdi, .LC0[rip]
call puts@PLT
mov eax, 0
pop rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size func, .-func
.section .rodata
.LC1:
.string "In main"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 16
mov eax, 0
call func
cdqe
lea rdx, 0[0+rax*4]
lea rax, arr[rip]
add rax, rdx
mov QWORD PTR -8[rbp], rax
cmp QWORD PTR -8[rbp], 0
je .L4
lea rdi, .LC1[rip]
call puts@PLT
.L4:
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (GNU) 7.3.0"
.section .note.GNU-stack,"",@progbits
我希望我能对这里的处理提供一些合乎逻辑的解释,但我只能记录下来。看来我们需要和 gcc 名单上的人谈谈。
在 'if' 内部的地址计算中丢弃的副作用
这似乎是 gcc 中的一种回归,取决于单个发行版是否应用了足够的补丁来掩盖它。这是工作中的 gcc 错误。 Bug 84607