2012-05-08 5 views
8

Nie rozumiem, jak to ma działać.Dlaczego wbudowany asembler GCC wymaga informacji o przenikaniu, ale MSVC nie jest

GCC to wbudowany asembler jest trudny do uzyskania, ale bardzo konkretny w zaznaczaniu informacji typu clobbering, dzięki czemu kompilator wie, co robisz.

Program wbudowany Microsoft Visual C++ jest naprawdę łatwy w użyciu (zawsze wydaje się, że działa), ale nie mam pomysłu, jakie gwarancje lub założenia dotyczą kodu.

Czy VC++ próbuje "automatycznie wykryć", które rejestry są zablokowane? Skąd wiadomo, w jaki sposób zmienione zostaną rejestry i wskaźnik stosu? Czy ma jakieś założenia? Jeśli tak, jak obejść te założenia?

Odpowiedz

19

Jak, dlaczego GCC nie robi tego tak MSVC robi, istnieje kilka powodów:

  1. GCC jest retargettable kompilator, ale składnia montaż jest po prostu surowy tekst. Aby wykrywanie clobbera było automatyczne, GCC musiałoby przeanalizować język asemblera, aby zrozumieć, które rejestry są poddawane "clobbered" (w tym niejawnie "clobbered" instrukcjami, których opcodes nie wymieniają rejestru). Musiałoby to działać we wszystkich architekturach. Obecnie GCC nie analizuje języka asemblera; wkleja go do wyjścia zespołu, po wykonaniu podstawień %. Chodzi o generowanie i unikanie analizowania.

  2. W języku inline assembler GCC, rejestry typu clobbering są raczej wyjątkiem niż regułą. Powodem jest to, że jest to język bardziej wyrafinowany niż w MSVC. Wbudowany język asemblera GCC przydziela rejestry. Więc zwykle nie używasz bezpośrednio czegoś takiego jak %eax, ale kod taki jak %0, dla którego GCC zastępuje dostępny rejestr. (Aby to zrobić, kompilator nie musi rozumieć języka asemblerowego - wyrażasz ograniczenia, które zapewniają, że GCC zastępuje odpowiedni rejestr dla %0, który pasuje do użycia). Potrzebujesz tylko odrzutu, jeśli kod twojego zespołu nadpisuje mocno -kodowane rejestry, a nie jeśli nadpisuje argumenty wynikowe przydzielone dla ciebie przez GCC.

Należy zauważyć, że z montażem inline GCC, nie trzeba pisać kod, który ładuje swoje argumenty asemblerze od wyrażeń C, które produkują swoje początkowe wartości, lub który przechowuje swoje argumenty wynik w okolicy miasta C.Na przykład po prostu wyrażasz, że ma być argument wejściowy typu "r" (rejestr), który pochodzi od wyrażenia foo->bar + 1. GCC przydziela rejestr i generuje kod w celu załadowania go z foo->bar + 1, a następnie zastępuje wystąpienia %0 w szablonie złożenia nazwą tego rejestru.

+2

+1, bardzo wyrafinowana odpowiedź na kolejne pytanie OP :) –

+0

# 2 był bardzo przydatnym komentarzem, nie miałem o tym pojęcia! Dzięki! :) – Mehrdad

+0

w 1. powyżej mówi: * "Pomysł polega na generowaniu i unikaniu analizowania" * wydaje mi się jednak, że kompilator odbierający informacje o elementach clobbered wymaga mimo to parsowania, prawda? Wychodząc z - prawdopodobnie niepoprawnego - wrażenia, że ​​"wbudowany montaż może nie mieć na celu zwiększenia niezależności architektury, i całkiem łatwo będzie montować się na platformie", byłoby pięknie, gdyby był słowniczek, który zapewniałby dopracowaną informację wspomaganą przez kompilator , aby pozwolić programistom zapomnieć o rzeczach. Czy pojawiły się pewne zmiany, ponieważ pytanie zadano w 2012 roku? – humanityANDpeace

4

the docs Cytat:

Podczas korzystania __asm ​​napisać asemblera w C/C++ funkcji, nie trzeba zachować EAX, EBX, ECX, EDX, ESI, EDI lub rejestrów. Na przykład w przykładzie POWER2.C w Writing Functions with Inline Assembly funkcja power2 nie zachowuje wartości w rejestrze EAX. Jednak użycie tych rejestrów wpłynie na jakość kodu, ponieważ alokator rejestru nie może ich użyć do przechowywania wartości w blokach __asm. Ponadto, używając EBX, ESI lub EDI w wbudowanym kodzie, zmuszasz kompilator do zapisywania i przywracania tych rejestrów w prologu i epilogu funkcji.

Należy zachować inne rejestry, których używasz (takie jak rejestry DS, SS, SP, BP i flagi) dla zakresu bloku __asm. Powinieneś zachować rejestry ESP i EBP, chyba że masz jakiś powód, aby je zmienić (na przykład zmienić stosy). Zobacz także Optimizing Inline Assembly.

+0

+1 czuje się tak głupio, nie patrząc na to w dokumentach ... – Mehrdad

+1

Coś jednak zadaje pytanie: dlaczego GCC tego nie robi? – Mehrdad

+2

Podsumowując dla naszych innych czytelników: "tak, MSVC automatycznie wykrywa, które rejestry są zbite, podczas gdy GCC wymaga oznaczenia ich jawnie." – Crashworks

Powiązane problemy