Forum: Compiler & IDEs Übersetzen GCC in Assambler


von Maria K. (maria_k)


Lesenswert?

Hi,

ich wäre sehr dankbar, wenn mir jemand sagen könnte, wie der 
Assambler-Code hinter folgendem Makro aussieht, bzw. wie der gcc dieses 
Makro interpretieren würde:
1
#define mfmsr()         ({  unsigned int _rval;         \
2
                            __asm__ __volatile__ (      \
3
                                "mfs\t%0,rmsr\n" : "=d"(_rval) \
4
                            );                          \
5
                            _rval;                      \
6
                        })

Das Makro stammt aus einem Header für Xlinx Microblaze. Da ich mit 
dieser Syntax wirklich nicht viel anfangen kann, würde mir eine 
detailierte Erklärung wirklich weiterhelfen.
(Was bedeuten in diesem Kontext
1
 __volatile__
,
1
 \t%0
,
1
\n" : "=d"(_rval)
)

Schon mal Danke im voraus. Gruß Maria

von Yalu X. (yalu) (Moderator)


Lesenswert?

1
#define mfmsr()
 -> Definiert das Makro mfmsr (move from machine status register)
1
unsigned int _rval;
 -> Definition einer temporären Variable
1
__asm__
 -> Jetzt kommt Inlineassemblercode.
1
__volatile__
 -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
    wegoptimieren oder ihn aus einer Schleife vor die Schleife
    verschieben.
1
"mfs\t%0,rmsr\n" : "=d"(_rval) \
 -> Beschreibung des zu generierenden Assemblercodes
1
   mfs\t%0,rmsr\n
    -> Pattern für Assemblerbefehl. Für %0 wird etwas eingesetzt, was
       nach dem Doppelpunkt genauer spezifiziert wird.
1
      mfs
       -> move from special purpose register
1
      rmsr
       -> register "machine status register"
1
   "=d"(_rval)
    -> Spezifikation dafür, was für %0 eingesetzt werden soll
1
      =
       -> Gibt an, dass %0 ein Output ist.
1
      d
       -> Gibt an, dass %0 ein General-Register sein soll. Der Compiler
          wird also für %0 eines der Register r0—r31 einsetzen.
1
      (_rval)
       -> In dieser C-Variable soll der Inhalt von %0 am Schluss landen.
          Ist _rval eine Registervariable, wird der Compiler dieses
          Register für %0 einsetzen, so dass der msr-Befehl den Status
          direkt in _rval schreiben kann. Liegt _rval im RAM, wird
          der Compiler einen zusätzlichen Assemblerbefehl generieren,
          der den Inhalt des ausgewählten Registers (r0—r31) an die
          entsprechende RAM-Adresse kopiert.
1
_rval;
 -> Rückgabewert des vom Makro erzeugten C-Blocks.

Alles zusammengenommen macht das Makro also den Inhalt des Machine-
Statusregisters für das C-Programm verfügbar. Die Anweisung
1
  status = mfmsr();

schreibt den Inhalt des Statusregisters in die Variable status.

Noch viel mehr zu diesem Thema steht im GCC-Manual in diesen Kapiteln:

  http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  http://gcc.gnu.org/onlinedocs/gcc/Constraints.html
  http://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
  http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:

>  __volatile__
>
>  -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
>     [...] aus einer Schleife vor die Schleife verschieben.

Doch, darf er wohl.

Es darf nicht mit anderen volatile-Operationen vertauscht werden.

Mit "normalen" Operationen darf es vertauscht werden — sofern die 
Abhängigkeiten dies zulassen. Dies schliesst auch Speicherzugriffe ein 
sofern diese nicht volatile sind.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Johann L. schrieb:
>>  __volatile__
>>
>>  -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
>>     [...] aus einer Schleife vor die Schleife verschieben.
>
> Doch, darf er wohl.

Sicher?

> Es darf nicht mit anderen volatile-Operationen vertauscht werden.
>
> Mit "normalen" Operationen darf es vertauscht werden — sofern die
> Abhängigkeiten dies zulassen.

Schon richtig, aber das von mir Geschriebene widerspricht dem ja auch
nicht. Ich war eigentlich der Auffassung, dass ein asm mit volatile, das
in einer sich 100mal drehenden Schleife steht, auch tatsächlich 100mal
ausgeführt wird. Ohne volatile kann der Compiler das asm vor die
Schleife stellen, wenn der Input nicht von Berechnungen in der Schleife
abhängt.

Liege ich da falsch?

Zumindest in diesem Beispiel verhält sich der Compiler genau nach meinen
Vorstellungen:
1
uint8_t x;
2
3
void test_volatile(void) {
4
  uint8_t i;
5
6
  for(i=0; i<10; i++) {
7
    __asm__ __volatile__ ("ldi %0,1" : "=d" (x));
8
  }
9
}

Mit __volatile__:
1
test_volatile:
2
  ldi r24,lo8(10)
3
.L2:
4
  ldi r25,1  ; <-- in der Schleife
5
  sts x,r25
6
  subi r24,lo8(-(-1))
7
  brne .L2
8
  ret

Ohne __volatile__:
1
test_volatile:
2
  ldi r24,lo8(10)
3
  ldi r25,1 ; <-- vor der Schleife
4
.L2:
5
  sts x,r25
6
  subi r24,lo8(-(-1))
7
  brne .L2
8
  ret

Anmerkung: Das Beispiel ist für den AVR, da ich mich mit dem Microblaze
nicht auskenne. Das sollte aber in diesem Zusammenhang nichts ausmachen.

von Maria (Gast)


Lesenswert?

Vielen Dank,

für die wirklich ausführlichen und vor allem hilfreichen 
Antworten/Links.


Gruß
Maria

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Yalu X. schrieb:
> Johann L. schrieb:
>>>  __volatile__
>>>
>>>  -> Der Compiler darf den nachfolgenden Assemblercodeabschnitt nicht
>>>     [...] aus einer Schleife vor die Schleife verschieben.
>>
>> Doch, darf er wohl.
>
> Sicher?

Ja :-)

>> Es darf nicht mit anderen volatile-Operationen vertauscht werden.
>>
>> Mit "normalen" Operationen darf es vertauscht werden — sofern die
>> Abhängigkeiten dies zulassen.
>
> Schon richtig, aber das von mir Geschriebene widerspricht dem ja auch
> nicht. Ich war eigentlich der Auffassung, dass ein asm mit volatile, das
> in einer sich 100mal drehenden Schleife steht, auch tatsächlich 100mal
> ausgeführt wird.

Ja, das stimmt. Die Seiteneffekte müssen natürlich die gleichen sein.

Hier ein etwas komplexeres Beispiel:
1
#include <stdint.h>
2
3
uint8_t x;
4
uint8_t y;
5
6
void test_volatile (void)
7
{
8
    uint8_t i;
9
10
    for (i=0; i < 10; i++)
11
    {
12
        y = i;
13
        __asm__ __volatile__ ("ldi %0,1" : "=d" (x));
14
    }
15
}
 
und übersetzt mit avr-gcc-4.7.1 -O3
 
1
test_volatile:
2
  ldi r24,1
3
  ldi r24,1
4
  ldi r24,1
5
  ldi r24,1
6
  ldi r24,1
7
  ldi r24,1
8
  ldi r24,1
9
  ldi r24,1
10
  ldi r24,1
11
  ldi r24,lo8(9)
12
  sts y,r24
13
  ldi r24,1
14
  sts x,r24
15
  ret

Was hier nicht geht, ist das Schreiben von y mit dem von x zu 
vertauschen. Allerdings nicht wegen dem volatile, sondern wegen den 
Aliasing-Rules.

Bestübde der Seiteneffekt des asm jedoch in Umkonfigurieren der 
Hardware, zB Setzen von Segmentregistern die die Speicherzugriffe 
beeinflussen, hätte man mit dem obigem Code ein Problem, denn x bzw y 
hängen nicht vom asm ab.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.