Wymuś GCC, aby wypchał argumenty na stosie przed wywołaniem funkcji (za pomocą instrukcji PUSH)
Zacząłem tworzyć mały 16-bitowy system operacyjny w GCC / G ++. Używam kompilatora krzyżowego GCC, który skompilowałem pod Cygwinem, umieszczam asm (". Code16gcc n") jako pierwszą linię każdego pliku .CPP, używając składni Intel ASM i linii poleceń do kompilacji i łączenia Plik .CPP wygląda tak:
G++: i586-elf-g++ -c $(CPP_FILE) -o $(OBJECT_OUTPUT) -nostdinc -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fpermissive -masm=intel
LD: i586-elf-ld -T $(LD_SCRIPT) $(OBJECT_OUTPUT) -o $(BINARY_OUTPUT)
Problemem, przed którym obecnie stoję, jest sposób, w jaki GCC tłumaczy kod wywołujący funkcje na zespół.
Aby być bardziej szczegółowym, zamiast używać instrukcji PUSH do przekazywania argumentów, GCC "oblicza" przesunięcia względem ESP, których argumenty powinny być zlokalizowane, a następnie używa instrukcji MOV do ręcznego zapisu stosu.
Nie jest to dla mnie korzystne, ponieważ polegam na instrukcji PUSH w moim kodzie zespołu. Aby zilustrować mój problem jaśniej, weź te dwie funkcje:
void f2(int x);
void f1(){
int arg = 8;
asm("mov eax, 5");
asm("push eax");
f2(arg);
asm("pop eax");
}
void f2(int x){
}
W funkcji f1 zapisuję EAX za pomocą instrukcji PUSH i oczekiwałbym przywrócenia go do 5 po wywołaniu f2 i wykonaniu instrukcji „POP EAX”. Okazuje się jednak, że EAX staje się 8, a nie 5. To dlatego, że GODZIENNY KOD GCC generuje wygląda w ten sposób (ja również dodałem źródło dla jasności):
void f1()
C++: {
push ebp
mov ebp,esp
sub esp,byte +0x14
C++: int arg = 8;
mov dword [ebp-0x4],0x8
C++: asm("mov eax, 5");
mov eax,0x5
C++: asm("push eax");
push eax
C++: f2(arg);
mov eax,[ebp-0x4]
mov [dword esp],eax =======>>>>>> HERE'S THE PROBLEM, WHY NOT 'PUSH EAX' ?!!
call f2
C++: asm("pop eax");
pop eax
C++: }
o32 leave
o32 ret
void f2(int x)
C++: {
push ebp
mov ebp,esp
C++: }
pop ebp
o32 ret
Próbowałem użyć niektórych flag kompilacji G ++, takich jak -mpush-args lub -mno-push-args i innej, której nie pamiętam, a GCC nadal nie chce używać PUSH. Używana przeze mnie wersjai586-elf-g++ (GCC) 4.7.2
(Kompilator krzyżowy ponownie skompilowany w Cygwin).
Z góry dziękuję!
AKTUALIZACJA: Oto strona, którą znalazłem:http://fixunix.com/linux/6799-gcc-function-call-pass-arguments-via-push.html
Wydaje się to naprawdę głupie dla GCC, biorąc pod uwagę, że ogranicza to użyteczność montażu inline dla złożonych rzeczy. :( Proszę zostawić odpowiedź, jeśli masz sugestię.