Ich mache mehrere Experimente mit x86
asm versuchen zu sehen, wie gängige Sprachkonstrukte in Assembly mappen. In meinem aktuellen Experiment versuche ich speziell zu sehen, wie C-Sprachzeiger der registerindirekten Adressierung zugeordnet werden. Ich habe eine ziemlich hallo-Welt wie Zeiger Programm geschrieben:In x86, warum habe ich die gleiche Anweisung zweimal, mit umgekehrten Operanden?
#include <stdio.h>
int
main (void)
{
int value = 5;
int *int_val = &value;
printf ("The value we have is %d\n", *int_val);
return 0;
}
und an folgenden asm zusammengestellt werden: gcc -o pointer.s -fno-asynchronous-unwind-tables pointer.c
: [1] [2]
.file "pointer.c"
.section .rodata
.LC0:
.string "The value we have is %d\n"
.text
.globl main
.type main, @function
main:
;------- function prologue
pushq %rbp
movq %rsp, %rbp
;---------------------------------
subq $32, %rsp
movq %fs:40, %rax
movq %rax, -8(%rbp)
xorl %eax, %eax
;----------------------------------
movl $5, -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 $0, %eax
call printf
;----------------------------------
movl $0, %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
Mein Problem ist, dass ich don verstehe nicht, warum es zweimal den Befehl movq
enthält, mit umgekehrten Operanden. Kann mir jemand das erklären?
[1]: Ich möchte vermeiden, dass mein asm-Code mit cfi-Anweisungen durchsetzt ist, wenn ich sie überhaupt nicht brauche.
[2]: Meine Umgebung ist Ubuntu 14.10
, gcc 4.9.1
(von ubuntu geändert) und Gnu assembler (GNU Binutils for Ubuntu) 2.24.90.20141014
, konfiguriert x86_64-linux-gnu
Wenn Sie gcc nicht zur Optimierung auffordern, wird es einen * extrem * dummen Code erzeugen. Wie Sie gesehen haben, speichert es alle lokalen Variablen auf dem Stack, selbst wenn es leicht in einem Register gespeichert werden könnte. Um vernünftigen Code zu erhalten, sagen Sie gcc zur Optimierung mit '-O3'. – EOF
Ich kann nur den EOF-Kommentar wiedergeben. Ich finde, dass "-O" für mich am lesbarsten ist: "-O3" kann Transformationen anwenden, die die Rückverfolgbarkeit des Quellcodes in der Assembly erschweren. Aus dem gleichen Grund, in dem Sie '-fno-asynchronous-unwind-tables' verwendet haben, mögen Sie auch' -fomit-frame-pointer' (für einfache Funktionen ist die resultierende Assembly tatsächlich leichter und einfacher zu folgen). Lesen Sie nicht den Code, der mit '-O0' generiert wurde, es sei denn, Sie haben Zeit zu verschwenden. –
@EOF Ja, ich habe gesehen, was es mit '-O3' macht, und während es sauberer ist, hat es meine Zeiger (und weit mehr) optimiert, und auf diese Weise kann ich verlieren, was ich ursprünglich sehen wollte: Wie Zeigern zuordnen, um indirekte Adressierung zu registrieren. – NlightNFotis