Angenommen, ich habe Pseudo-Code C wie unten:Kann Befehl Reihenfolge Cross Function Call?
int x = 0;
int y = 0;
int __attribute__ ((noinline)) func1(void)
{
int prev = x; (1)
x |= FLAG; (2)
return prev; (3)
}
int main(void)
{
int tmp;
...
y = 5; (4)
compiler_mem_barrier();
func1();
compiler_mem_barrier();
tmp = y; (5)
...
}
Angenommen dies ein Single-Threaded-Prozess ist so brauchen wir nicht über Sperren zu kümmern. Und angenommen, der Code läuft auf einem x86-System. Nehmen wir an, der Compiler führt keine Neuordnung durch.
Ich verstehe, dass x86-Systeme nur Schreib-/Leseanweisungen neu ordnen können (Lesevorgänge können mit älteren Schreibvorgängen an verschiedenen Speicherorten neu angeordnet werden, aber nicht mit älteren Schreibvorgängen an denselben Speicherort). Aber es ist mir nicht klar , wenn Call/Ret-Anweisungen als WRITE/READ Anweisungen betrachtet werden. Also hier sind meine Fragen:
Auf x86-Systemen, wird "Anruf" als WRITE-Anweisung behandelt? Ich nehme an, da call die Adresse an den Stack schickt. Aber ich habe kein offizielles Dokument gefunden, das das offiziell sagt. Also bitte hilf mit zu bestätigen.
Aus dem gleichen Grund, wird "ret" als eine READ-Anweisung behandelt (da es die Adresse aus dem Stapel platzt)?
Eigentlich kann "ret" Anweisung innerhalb der Funktion neu geordnet werden. Zum Beispiel, kann (3) vor (2) im folgenden ASM-Code ausgeführt werden? Das ergibt für mich keinen Sinn, aber "ret" ist keine Serialisierungsanweisung. Ich habe im Intel-Handbuch keinen Platz gefunden und gesagt, dass "ret" nicht nachbestellt werden kann.
Im obigen Code kann (1) vor (4) ausgeführt werden? Vermutlich können Leseanweisungen (1) vor den Schreibanweisungen (4) neu geordnet werden. Die Anweisung "call" kann einen "jmp" -Teil haben, aber mit spekulativer Ausführung .... Ich denke, dass es passieren kann, aber ich hoffe, dass jemand, der mit diesem Thema vertrauter ist, dies bestätigen kann.
Im obigen Code kann (5) vor (2) ausgeführt werden? Wenn "ret" als eine READ-Anweisung betrachtet wird, nehme ich an, dass dies nicht passieren kann. Aber ich hoffe, dass es jemand bestätigen kann.
Bei der Assembler-Code für func1() benötigt wird, sollte es so etwas wie sein:
mov %gs:0x24,%eax (1)
orl $0x8,%gs:0x24 (2)
retq (3)
Bitte helfen. Vielen Dank!
Fragen Sie sich: Kann die Funktion vom Compiler eingebunden werden? –
Nehmen wir an, dass die Funktion nicht inline ist. Wenn die Funktion inline ist, weiß ich, was passieren kann. – yacc45
Funktionen sind natürlich Compiler-Umordnungsbarrieren. Aber für den Prozessor, afaik, erzwingen weder 'call' noch 'ret' die Serialisierung. Siehe [Intel 64 und IA32 Architecture] (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462 .pdf) 8.3 Serialisierungsanweisungen. –