2014-05-08 4 views
5

Mir wurde eine Aufgabe zugewiesen, die theoretisch nicht zu schwer ist. Eine C-Variable sollte mit Assembler-Code (asm) geändert werden. Ich habe dies getan und es funktioniert, aber der zweite Teil der Aufgabe ist, das gleiche ohne Platzhalter (%) zu tun.Assembler in C ohne Platzhalter verwenden

Ich bin hier ratlos und nach einigen Recherchen habe ich noch keine Lösung gefunden. Wie kann ich auf C-Variablen im Assembler-Code zugreifen oder diese manipulieren, ohne Platzhalter zu verwenden, um die Variable zu erhalten?

Hier ist der Code mit Platzhalter:

volatile uint8_t number = 1; 
    volatile uint8_t *number_pointer = &number; 

    asm volatile(
     "ld r20, %a0" "\n\t" 
     "lsl r20" "\n\t" 
     "st %a0, r20" "\n\t" 
     "breq resetten" "\n\t" 
     "ret" "\n\t" 

     "resetten:" "\n\t" 
     "ldi r20, 1" "\n\t" 
     "st %a0, r20" 
      : "+e" (number_pointer) 
    ); 

Kurz gesagt: Wie kann ich auf und ändern "number_pointer" ohne% mit? (Der Code verdoppelt "Zahl", bis es 128 ist, dann beginnt es wieder mit 1.)

+0

Wenn die zu ändernde Variable lokal (auf dem Stapel) ist, können Sie compilerabhängige Annahmen darüber machen, wo sich die Variable im Speicher befindet, relativ zum Stapelzeiger. –

+0

Sie sollen ein zweites ':' hinzufügen, um Variablen in Register einzutragen (wie 'asm (" blabla "::" a "(number_pointer));), das würde aber number_pointer in eax ... aber verwenden AT & T-Syntax würden Sie immer '%% eax' verwenden, um darauf zuzugreifen. Wenn die Anforderung nicht '%' verwendet (wie Sie am Ende andeuten), dann funktioniert das nicht ... wenn die Anforderung nicht __placeholders__ verwendet, dann würde das passieren (Sie würden ein Register verwenden). – Jcl

+1

Wie wäre es, number_pointer als statisch oder global zu deklarieren? Dann können Sie direkt von der ASM über den Symbolnamen darauf zugreifen. Ich würde es nicht für Produktionscode empfehlen, aber für das Lösen von Rätseln sollte es funktionieren. –

Antwort

1

Davids Vorschlag zu kommentieren (Ich würde dies als Kommentar posten, wenn ich genug Reputation hatte): Verwenden Sie den Hinweis "Erinnerung" im verklemmten Feld, wie in asm ("nop" ::: "Erinnerung");

Dies sagt gcc, dass die asm-Anweisung Speicher modifiziert und die Variablen müssen neu geladen werden usw.

Zum Beispiel mit

static int foo; 
int bar() 
{ 
    foo = 1; 
    __asm__("":::"memory"); 
    return foo; 
} 

bekommen wir

Dump von Assembler-Code für Funktionsleiste:

0x0000000000000000 <+0>:   movl $0x1,0x0(%rip)  # 0xa <bar+10> 
    0x000000000000000a <+10>:  mov 0x0(%rip),%eax  # 0x10 <bar+16> 
    0x0000000000000010 <+16>:  retq 

während ohne die "Erinnerung" th Das erneute Laden des Variablenwerts fehlt.

+0

Dies kann zwar funktionieren, es kann jedoch zu zusätzlichen Leistungsproblemen führen. Da "Speicher" bedeutet, dass der ASM ALLEN Speicher lesen/schreiben kann, muss der Compiler möglicherweise mehr als nur das eine Register löschen (und neu laden). Auch hier ist die bessere Lösung, die Variable nur als Eingabe oder Ausgabe aufzulisten. –

+0

Ja, das ist verständlich, die richtige Verwendung von Ein- und Ausgängen ist immer die bevorzugte Lösung. Im Kontext der Frage von OP ist dies explizit keine Option, also müssen Sie "Speicher" auflisten, wenn Sie in eine globale Variable oder in einen anderen Speicher schreiben wollen - ohne sie könnte das Programm leicht sein schneller, aber es kann auch falsch sein, abhängig davon, wie der Compiler das optimiert, was er für invariante Werte hält. – akruppa

Verwandte Themen