Assembler w Delphi

0

Witam. Zacznę od tego ze w assemblerze piszę od kilku godzin.
Potrzebowałem funkcji do zapisywania i odczytywania bitów.

Oto owoc mojej pracy:

program Project1;
{$APPTYPE CONSOLE}

function GetBit(Val, Index: Byte): Byte;
asm
      MOV  CL, DL
      SHR  AL, CL
      AND  AL, 01h
end;

procedure PutBit(Val: PByte; Index, Bit: Byte);
asm
      AND EDX, 0ffh
      CMP CL, 00h
      JE  @lb1
      BTS [EAX], DX
      JMP @end
@lb1: BTR [EAX], DX
@end: // end
end;

var
  B: Byte;
  I: Integer;
begin
  B := 138; // 10001010b
  PutBit(@B, 5, 1); // 10101010b
  for I := 7 downto 0 do Write(GetBit(B, I));
  ReadLn;
end.

Wygląda, że działa. Mam tylko kilka pytań:

  1. Zauważyłem że argumenty trafiają do rejestrów tyle że jakoś dziwnie (A, D i C) czy zawsze tak jest?
  2. Jak argument Index typu Byte jest w DL to w całym EDX jest jakaś inna liczba. Dlaczego?
  3. Czy zawsze wynik funkcji trzeba wstawić do EAX, AX lub AL ?
  4. W funkcji GetBit tam gdzie jest SHR AL, CL; próbowałem wstawić DL zamiast CL, ale program się nie chciał skompilować. Czemu tylko CL ?
  5. Czy te funkcje można napisać lepiej. Jeżeli tak to jak?
  6. Jak napisać funkcję, która zwróci 4 argument? Chodzi mi o ten tajemniczy stos? Czytałem gdzieś, że tam trafiają argumenty, które nie trafią do rejestrów. Próbowałem coś kombinować, ale nic mi z tego nie wychodziło.
0
  1. Domyslnie, polecam fraze calling conventions w hlp lub google.
  2. Bo nie ma sensu zerowac rejestru (jest tam jakas przypadkowa liczba a cie nie i tak interesuje tylko 8 bitow z EDX.
  3. Patrz 1 :)
  4. Ogolnie ECX jest wykorzystywany do roznego rodzaju loopow, to taka jego wlasciwosc :)
  5. Result := (Value shr Index) and 1; // :P, naprawde nie ma sensu zaprzegac do takich rzeczy asma.
  6. No coz, do opeacji na stosie sluza instrukcje POP i PUSH lub kazde inne operujace na pamieci dzieki ESP (w ktorym jest polozenie wierzcholka stosu). Co kompilator to inaczej odklada parametry wiec tu raczej nic nie moge podpowiedziec.
0
  1. Nie ten dział - to powinno być w Delphi/Pascal...
  2. Poczytaj o konwencjach wywołania.
  3. Zgadzam się z Wolverinem :)
  4. Czasami nie - zobacz Asm
  5. Tylko dla instrukcji SHL z drugim parametrem stałym lub rejestrem licznika (ECX, CX, CL) istnieją opkody (odpowiedniki w kodzie maszynowym). Dla innych instrukcji obsługiwana jest tylko jedna rodzina rejestrów w danym miejscu (np. OUT przyjmuje dla pierwszego słowo maszynowe lub DX, dla drugiego EAX, AX, AL lub stałą wartość)
  6. Na pewno można napisać czytelniej ;P Odwołuj się do parametrów przy pomocy nazw. I nie tylko do tych odkładanych na stos.
  7. Patrz 5.
0

Dziękuję serdecznie za odpowiedzi.
Poczytałem trochę.
Argumenty funkcji znalazłem, ale dopiero pod ESP+8 niezależnie od konwencji wywołania. (różnica jest tylko w kolejności)
No i tu jest właśnie pytanie, czemu 8 bajtów dalej? Co jest wcześniej, nie potrafiłem tego zidentyfikować.

BTW udało mi się napisać funkcję PutBit lepiej: (te BTS i BTR są jakieś wolne)

procedure PutBitA(Val: PByte; Index, Bit: Byte);
asm
      PUSH CX;
      MOV  CL, DL;
      MOV  DL, 01h
      SHL  DL, CL
      POP  CX;
      CMP  CL, 00h
      JE   @lb1
      OR   [EAX], DL
      JMP  @end
@lb1: NOT  DL
      AND  [EAX], DL
@end: // end
end;

ale potem napisałem ją w Delphi i okazała się być szybsza o kilkanaście milisekund przy dużych danych:

procedure PutBitD(Val: PByte; Index, Bit: Byte);
var
  B: Byte;
begin
  B := 1 shl Index;
  if Bit = 0 then
    Val^ := Val^ and (not B)
  else
    Val^ := Val^ or B;
end;

dziwne bo jak ją oglądałem w debugerze to wyglądała podobnie tylko jest TEST zamiast CMP i jakiś rejestr ESI użyty.

Jeszcze raz dzięki za pomoc.

0

Te 8 bajty odklada instrukcja CALL, ktora zostawia na stosie stary IP i CS zeby pozniej mozna bylo powrocic z funkcji.

0
Wolverine napisał(a)

Te 8 bajty odklada instrukcja CALL, ktora zostawia na stosie stary IP i CS zeby pozniej mozna bylo powrocic z funkcji.

sorry, ale się nie zgodzę - tylko EIP, w końcu do delphi więc cs nie jest potrzebny /może w pascalu jest cs i ip ale i to i to ma po 2 bajty/... mnie to wygląda trochę jak zmienne lokalne funkcji wywołującej ew. zachowane rejestry... bez wrzucenia w\w kodu pod debugger lub disassember nie da się stwierdzić co tam jest faktycznie :/ Gdyby to była metoda klasy to pod esp+4 byłby this.

1 użytkowników online, w tym zalogowanych: 0, gości: 1