Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

asembler - wytłumaczenie początkującemu

joker999 27 Maj 2013 19:57 819 4
  • #1 27 Maj 2013 19:57
    joker999
    Poziom 2  

    Witam,
    mam prośbę o wytłumaczenie mi, fragmentu kodu, no może nie fragmentu a konwencji:
    piszę/napisałem program w c, który wywołuje w pewnym momencie asemblera.
    chodzi mi konkretnie o to czemu muszę na początku zrzucić zawartość ebx na stos, a na końcu ją przywrócić? (sprawdziłem -> bez tych dwóch linijek program nie działa, kompiluje się i odpala, ale wynik niejest poprawny)
    czytałem trochę o tym ale jedyne wzmianki jakie znalazłem mówiły:
    -tak, bo taka konwencja << najczęstsze
    -bo utracę dane z rejestrów bazowych
    mógłby ktoś mi to sprecyzować? co takiego jest w tym ebx i co się dzieję kiedy to tracę?

    Code:

    .global operacja

        operacja:
            pushl %ebx
            (...)
            popl %ebx
        ret

    0 4
  • #2 27 Maj 2013 20:27
    leoha
    Poziom 16  

    joker999 napisał:
    -tak, bo taka konwencja << najczęstsze

    I prawdziwie. Poczytaj o konwencjach stosowanych w architekturze x86 (x86_64) tutaj to zrozumiesz, zwłaszcza o cdecl, której zapewne używa twój kompilator.

    0
  • #3 28 Maj 2013 08:59
    Mr_Unk
    Poziom 17  

    Używanie argumentu "bo taka jest konwencja" nie różni się niczym od stwierdzenia
    "bo tak".

    Aby zrozumieć problem, musisz, przede wszystkim zrozumieć, jak działa asembler i czym są wspomniane rejestry (częstym problemem osób programujących wyłącznie w jęz. wysokopoziomowych jest niemożność odróżnienia ich funkcjonalności od zmiennych).
    Tak więc na początek:

    Cytat:
    Rejestr jest to specjalny obszar pamięci wewnątrz procesora służący do przechowywania wartości liczbowych.


    Do tej definicji warto jeszcze dodać informację, że aby wykonać operację arytmetyczną bądź logiczną (nawet proste sumowanie), argumenty (sumowane liczby) muszą znajdować się w określonych rejestrach, a wynik tego działania także trafia do określonego rejestru. Po prostu nie da się tego zrobić inaczej.

    EAX i EBX są właśnie tymi dwoma rejestrami, w których najczęściej umieszcza się argumenty, stąd nie można w nich niczego przechowywać dłużej (bo są potrzebne przy kolejnej operacji).
    Stąd właśnie bierze się konieczność odkładania na stos - w innym wypadku, nie masz pewności, czy EBX nie będzie brał udziału w jakichś operacjach dalej, a w znakomitej większości przypadków tak właśnie będzie, zatem jego zawartość trzeba będzie nadpisać. I stąd w dużym uproszczeniu bierze się owa "konwencja".

    0
  • #4 28 Maj 2013 09:27
    Tomasz Gumny
    Poziom 27  

    Kompilator nie wie, które rejestry zmieniasz we wstawce asemeblerowej, dlatego najbezpieczniej jest zachować i odtworzyć zawartość wszystkich rejestrów, które zmieniasz (lub które mogą się zmienić).

    0
  • #5 28 Maj 2013 12:30
    leoha
    Poziom 16  

    Mr_Unk napisał:
    Używanie argumentu "bo taka jest konwencja" nie różni się niczym od stwierdzenia "bo tak".

    Przeczytaj jeszcze raz uważnie ten link, bo użyłem zupełnie innego argumentu.

    Cytat:

    The cdecl (which stands for C declaration) is a calling convention that originates from the C programming language and is used by many C compilers for the x86 architecture.[1] In cdecl, subroutine arguments are passed on the stack. Integer values and memory addresses are returned in the EAX register, floating point values—in the ST0 x87 register. Registers EAX, ECX, and EDX are caller-saved, and the rest are callee-saved. The x87 floating point registers ST0 to ST7 must be empty (popped or freed) when calling a new function, and ST1 to ST7 must be empty on exiting a function.

    Jak widzisz EBX jest callee-saved, wiec kompilator zakłada, ze jak przed wywłoaniem calla ustawi EBX na jakaś wartość to ta wartość będzie taka sama po powrocie z funkcji (i jest to konwecja, ale w znaczeniu troche innym niż podaje PWN, możliwe że bardziej odpowiednie słowo po polsku byłoby "standard" albo "norma"). Po prostu kompilator trzyma sie tego "standardu", i generuje tak kod, że oczekuje, że wszystkie rejestry oprócz EAX, ECX, EDX bedą miały po powrocie z funkcji taka samą wartość jak przed jej wywołaniem. Dlatego jak zmieniasz EBX w funkcji to kompilatorowi się "rozjeżdzają" dane.

    0