В x86, почему у меня одна и та же инструкция два раза, с обратными операндами?
Я провожу несколько экспериментов с x86
asm пытается увидеть, как общий язык создает карту в сборку. В моем текущем эксперименте я пытаюсь увидеть, как указатели языка C сопоставляются для регистрации-косвенная адресация. Я написал довольно Привет-мир, как программа указателя:
#include <stdio.h>
int
main (void)
{
int value = 5;
int *int_val = &value;
printf ("The value we have is %dn", *int_val);
return 0;
}
и скомпилировал его в следующий asm, используя:gcc -o pointer.s -fno-asynchronous-unwind-tables pointer.c
:[1][2]
.file "pointer.c"
.section .rodata
.LC0:
.string "The value we have is %dn"
.text
.globl main
.type main, @function
main:
;------- function prologue
pushq %rbp
movq %rsp, %rbp
;---------------------------------
subq , %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
;----------------------------------
movl , -20(%rbp) ; This is where the value 5 is stored in `value` (automatic allocation)
;----------------------------------
leaq -20(%rbp), %rax ;; (GUESS) If I have understood correctly, this is where the address of `value` is
;; extracted, and stored into %rax
;----------------------------------
movq %rax, -16(%rbp) ;;
movq -16(%rbp), %rax ;; Why do I have two times the same instructions, with reversed operands???
;----------------------------------
movl (%rax), %eax
movl %eax, %esi
movl $.LC0, %edi
movl , %eax
call printf
;----------------------------------
movl , %eax
movq -8(%rbp), %rdx
xorq %fs:40, %rdx
je .L3
call __stack_chk_fail
.L3:
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.9.1-16ubuntu6) 4.9.1"
.section .note.GNU-stack,"",@progbits
моя проблема в том, что я не понимаю, почему он содержит инструкцию movq
два раза, с обратной операндов. может кто-нибудь объяснить мне это?
[1]: я хочу избежать того, чтобы мой код asm перемежался директивами cfi, когда они мне вообще не нужны.
[2]: мое окружение Ubuntu 14.10
, gcc 4.9.1
(изменено ubuntu) и Gnu assembler (GNU Binutils for Ubuntu) 2.24.90.20141014
, настроено на target x86_64-linux-gnu
2 ответов
возможно, будет яснее, если вы реорганизуете свои блоки:
;----------------------------------
leaq -20(%rbp), %rax ; &value
movq %rax, -16(%rbp) ; int_val
;----------------------------------
movq -16(%rbp), %rax ; int_val
movl (%rax), %eax ; *int_val
movl %eax, %esi ; printf-argument
movl $.LC0, %edi ; printf-argument (format-string)
movl , %eax ; no floating-point numbers
call printf
;----------------------------------
первый блок выполняет int *int_val = &value;
, второй блок выполняет printf ...
. Без оптимизации, блоки независимы.
поскольку вы не делаете никакой оптимизации, gcc создает очень простой код, который делает каждый оператор в программе по одному, не глядя на любой другой оператор. Таким образом, в вашем примере он сохраняет значение в переменной int_val
, а затем следующая инструкция снова считывает эту переменную как часть следующего оператора. В обоих случаях он использует %rax
как временное значение для хранения, так как это первый регистр, обычно используемый для вещей.