У меня есть следующая программа на 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 с 64-битной x86.Я вызываю системный вызов для «записи» с 0 в качестве аргумента fd, потому что это стандартный вывод.
Если я скомпилирую под gcc с -O3, это не сработает.Просмотр кода сборки
.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», потому что в некоторых ситуациях это не сработало.