我有以下C程序
int main() {
char string[] = "Hello, world.\r\n";
__asm__ volatile ("syscall;" :: "a" (1), "D" (0), "S" ((unsigned long) string), "d" (sizeof(string) - 1)); }
我想在x86 64位Linux下运行。我将此系统调用称为“写入”,将0作为fd参数,因为它是stdout。
如果我在带有-O3的gcc下编译,则无法正常工作。看汇编代码
.file "test_for_o3.c"
.text
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
subq $40, %rsp
.cfi_def_cfa_offset 48
xorl %edi, %edi
movl $15, %edx
movq %fs:40, %rax
movq %rax, 24(%rsp)
xorl %eax, %eax
movq %rsp, %rsi
movl $1, %eax
#APP
# 5 "test_for_o3.c" 1
syscall;
# 0 "" 2
#NO_APP
movq 24(%rsp), %rcx
xorq %fs:40, %rcx
jne .L5
xorl %eax, %eax
addq $40, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 8
ret
.L5:
.cfi_restore_state
call __stack_chk_fail@PLT
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0"
.section .note.GNU-stack,"",@progbits
告诉我们gcc根本没有将字符串数据放入汇编代码中。相反,如果我将“ string”声明为“ volatile”,则可以正常工作。
但是,“易失性”的思想只是将其用于可以通过意外事件(从执行函数的角度)改变其值的变量,不是吗? “易失性”会使代码变慢得多,因此,如果可能,应避免使用它。
正如我想的那样,gcc必须假设“ string”的内容一定不能被忽略,因为指针“ string”被用作内联汇编中的输入参数(而gcc不知道内联汇编代码将是什么)这样做)。
如果这是gcc的“允许”行为,那么我在哪里可以阅读有关为-O3编写代码时必须了解的所有形式约束的更多信息?
第二个问题是“ volatile”语句和内联汇编指令的确切作用。我只是习惯用“ volatile”标记所有内联汇编指令,因为在某些情况下它不能正常工作。