2013-10-15 20 views
5

Piszę kod, aby tymczasowo użyć mojego własnego stosu do eksperymentów. To zadziałało, gdy użyłem dosłownego wbudowanego zespołu. Odblokowałem zmienne lokalizacje jako przesunięcia z ebp. Jednak chciałem, aby mój kod działał bez umieszczania w nim twardych adresów pamięci kodu, więc szukałem w GCC EXTENDED INLINE ASSEMBLY. To, co mam jest następujące:

volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER; 
volatile intptr_t old_stack_ptr = 0; 
asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

Punkt ten jest najpierw zapisać wskaźnik stosu do zmiennej old_stack_ptr. Następnie wskaźnik stosu (% esp) zostanie zastąpiony adresem, który zapisałem w pliku new_stack_ptr.

Mimo to okazało się, że GCC zapisuje% esp w old_stack_ptr, ale NIE zastępuje% esp z new_stack_ptr. Po głębszej kontroli, uważam, że to faktycznie rozszerzony mojego zespołu i dodaje swoje własne instrukcje, które są następujące:

mov -0x14(%ebp),%eax 
mov %esp,%eax 
mov %eax,%esp 
mov %eax,-0x18(%ebp) 

myślę GCC próbuje zachować% esp, bo nie ma to wyraźnie zadeklarowane jako operand "wyjścia" ... Mogłem być całkowicie w błędzie z tym ...

Naprawdę chciałem użyć rozszerzonego wbudowanego zestawu do tego, ponieważ jeśli nie, to wydaje mi się, że muszę "twardo kodować" lokalizację przestawia% ebp na wirtualny plik dziennika, a ja wolałbym używać takich nazw zmiennych, szczególnie dlatego, że ten kod musi działać w kilku różnych systemach, które wydają się zneutralizować moje zmienne w inny sposób, więc używając rozszerzonego wbudowanego zestawu pozwala mi jawnie y mówię o zmiennej lokalizacji ... ale nie rozumiem, dlaczego robi to dodatkowe rzeczy i nie pozwala mi zastąpić wskaźnika stosu tak, jak było wcześniej, odkąd zacząłem używać rozszerzonego zestawu, to robiłem.

Doceniam każdą pomoc !!!

+0

Nie jestem pewien, czy to pomaga, ale może '-fomit-frame-pointer' (który jest włączony z' -O1' i wyżej) wyeliminowałoby potrzebę martwienia się o '% ebp'. – DaoWen

+0

Dodatkowe rzeczy prawdopodobnie istnieją, ponieważ robisz debugowanie (bez optymalizacji), a GCC domyślnie przechwytuje potencjalne błędy. Wyszukaj "Sprawdzanie ramki stosu GCC", aby zobaczyć, jakie opcje oferuje GCC. – Skizz

Odpowiedz

8

OK, problem polega na tym, że gcc przypisuje wejście i wyjście do tego samego rejestru: eax. Chcesz powiedzieć gcc, że odkładasz wyjście przed użyciem wejścia, aka. "earlyclobber".

asm __volatile__("movl %%esp, %0\n\t" 
     "movl %1, %%esp" 
     : "=&r"(old_stack_ptr) /* output */ 
     : "r"(new_stack_ptr) /* input */ 
     ); 

Zwróć uwagę na znak & dla wyjścia. To powinno naprawić twój kod.

Aktualizacja: alternatywnie, można wymusić wejście i wyjście będzie ten sam rejestr i używać xchg, tak:

asm __volatile__("xchg %%esp, %0\n\t" 
     : "=r"(old_stack_ptr) /* output */ 
     : "0"(new_stack_ptr) /* input */ 
     ); 

Zawiadomienie "0" że mówi "umieścić to w tym samym rejestrze, jako argumentu 0 ".

+0

Dziękuję bardzo, bardzo! Nigdy wcześniej nie słyszałem o wcześniejszych odłamkach. Doskonała odpowiedź. Bardzo to doceniam. To naprawiło to. – Chad

+1

Przypuszczam, że alternatywnie można po prostu użyć 'xchg', a następnie wymusić wejście i wyjście do tego samego rejestru. – Jester