为什么一个简单的C";“你好,世界”;如果gcc-O3中没有“;易变的;?
我有下面的C程序为什么一个简单的C";“你好,世界”;如果gcc-O3中没有“;易变的;?,c,gcc,optimization,inline-assembly,C,Gcc,Optimization,Inline Assembly,我有下面的C程序 int main() { char string[] = "Hello, world.\r\n"; __asm__ volatile ("syscall;" :: "a" (1), "D" (0), "S" ((unsigned long) string), "d" (sizeof(string) - 1)); } 我想在Linux下用x86 64位运行它。我使用0作为fd参数调用“write”的系统调用,因为这是标准输出 如果我使用-O3在gcc下编译,它将不起作用。汇编代
int main() {
char string[] = "Hello, world.\r\n";
__asm__ volatile ("syscall;" :: "a" (1), "D" (0), "S" ((unsigned long) string), "d" (sizeof(string) - 1)); }
我想在Linux下用x86 64位运行它。我使用0作为fd参数调用“write”的系统调用,因为这是标准输出
如果我使用-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”,它可以正常工作
然而,“volatile”的概念只是用于变量,这些变量可以通过(从执行函数的角度)意外事件来更改其值,不是吗?“volatile”可能会使代码变得更慢,因此如果可能,应该避免使用
正如我所假设的,gcc必须假设“string”的内容不能被忽略,因为指针“string”在内联程序集中用作输入参数(gcc不知道内联程序集代码将如何处理它)
如果这是gcc的“允许”行为,那么在为-O3编写代码时,我在哪里可以阅读更多关于所有形式约束的信息
第二个问题是“volatile”语句和内联汇编指令究竟做了什么。我只是习惯于用“volatile”来标记所有内联汇编指令,因为在某些情况下它不起作用。显然是“simple C hello world”的意思,而不是我用来尝试的:
\uu asm\uuuvolatile(“syscall;”::“a”(1),“D”(0),“S”((无符号长)字符串),“D”(sizeof(字符串)-1:“memory”)}
@MichaelPetch:我想您正在寻找David Wohlferd演示如何使用虚拟内存操作数和指针输入操作数,告诉gcc指向内存的内容也是一个输入。(也是我提到的地方)。我一直想写一篇关于指针输入操作数的规范问答,因为它值得自己的问答。我提到了memory
clobber,因为它是最容易正确的,但是添加虚拟约束是更好的选择。另一种选择是\uuuasm\uuvolatile(“syscall;”::“a”(1),“D”(0),“S”((无符号长)字符串),“D”(sizeof(字符串)-1),“m”(*(const char(*[])string));]代码>“我用0作为fd参数调用“write”的系统调用,因为这是stdout。”嗯,fd0是stdin。stdout是fd1。