为什么一个简单的C";“你好,世界”;如果gcc-O3中没有“;易变的;?

为什么一个简单的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下编译,它将不起作用。汇编代

我有下面的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下编译,它将不起作用。汇编代码的研究

    .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。