Droga Przyjaciolko, zebra, odbicia

Maciej W. Rozycki macro w ds2.pg.gda.pl
Wto, 1 Lut 2000, 17:11:25 MET


On Tue, 1 Feb 2000, Rafal Maszkowski wrote:

> Probowalem uruchomic zebre. Bardzo pomagal mi przy tym agaran, ale poniewaz
> wojboj podsunal pomysl rozwiazania problemow z mrtd, wiec nie pilowalem do
> konca. Problemy (Sparc/Linux) polegaja na aligningu. Nie wiem dlaczego binaria
> sparcowe sie sypia (Bus Error) jezeli np. siegamy do inta, ktory ma adres
> 0xNNNNNNf, czemu kompilator tego nie przerabia na kilka mov-ow 1-bajtowych.

 Siegnijmy do zrodla -- dlaczego int nie jest wyrownany?  Kompilator nie
ma zwyczaju generowac zmiennych niewyrownanych, chyba ze poda mu sie
upakowana strukture (tj. z klauzula __attribute__((packed))), a wtedy
stosuje sekwencje rozkazow zastepczych.

 Nie znam SPARCa, ale przypuszczam, ze podobnie jak i inne procesory o
architekturze RISC, udostepnia on rozkazy typu "zaladuj dana niewyrownana
z lewej" i "zaladuj dana niewyrownana z prawej", ktore laduja w sposob
komplementarny lewa i prawa czesc rejestru (ilosc bitow ladowanych przez
kazdy z nich zalezy od wyrownania adresu).  Para takich rozkazow wystarcza
do zaladowania niewyrownanego inta.  Wymaga to jednak o 100% wiecej kodu i
czasu procesora, wiec normalnie sie tego rozwiazania nie stosuje, a w
zamian odpowiednio wyrownuje sie zmienne.

 Przy zapisie sytuacja jest analogiczna.

> Ktos to rozumie? Nie umiem tego rozwiazac globalnie, chociaz -O0 jakby nieco
> pomagalo, wyglada, ze wymaga to dlugich godzin hackowania.

 Pomaga, gdyz operacje typu memcpy() na blokach o stalych rozmiarach sa
przy wlaczonej optymalizacji kodowane przez gcc jako sekwencje rozkazow.
Np.: 

memcpy((int *)dst, (int *)src, 4);

to beda typowo dwa rozkazy procesora ("zaladuj" i "zapisz").  Z drugiej
strony, wolanie: 

memcpy((char *)dst, (char *)src, 4);

zostanie rozwiniete w dluzszy kod, uwzgledniajacy, ze zmienne typu char
moga miec dowolne wyrownanie, a nie tylko do wielokrotnosci 4, tak jak
int.  Przy braku optymalizacji wolane beda funkcje biblioteczne, ktore
zawsze musza jawnie sprawdzac wyrownanie adresow i postepowac odpowiednio. 

 Kod, w ktorym wystepuja zmienne niewyrownane w kontekstach innych niz w
upakowanych strukturach jest przede wszystkim zle napisany.  Tego rodzaju
objawy wystepuja np. przy nieostroznym rzutowaniu typow argumentow
funkcji.  Sposob wyeliminowania tego problemow z wyrownaniem zalezy od
konstrukcji konkretnych fragmentow kodu.

 Jednym ze sposobow na wyluskanie danych niewyrownanych, przydatnych np.
gdy mamy "wektor" danych o roznym rozmiarze (sytuacja spotykana np. przy
stosowaniu algorytmow kompresji danych) jest rzutowanie typu na upakowana
strukture.  Np. w kontekscie nastepujacej definicji:

typedef struct { int v __attribute__((packed)); } int_s;

nastepujace wyrazenie zwroci poprawna wartosc zmiennej x typu int,
niezaleznie od jej wyrownania: 

((int_s *)&(x))->v;

 Powyzsza metoda dziala dla egcs w wersji 1.1 i nowszych (wlaczajac w to,
oczywiscie, gcc 2.95).

 Oczywiscie, zamiast dlubac samodzielnie, mozna na to zwrocic uwage
(zapewne intelocentrycznemu) autorowi programu.

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: macro w ds2.pg.gda.pl, PGP key available        +




Więcej informacji o liście dyskusyjnej 6BONE-PL