Delphi + asm + skok warunkowy

0

Cześć, chciałem napisać sobie funkcję "silnia" w asmie w środowisku Borland Delphi 6.

Napisałem coś takiego:

function silnia_asm(x: integer): int64; assembler;
asm
  mov EAX, 1    {Ustawiam EAX na 1 - pierwszy czynnik}
  mov EBX, 1    {i drugi czynnik - licznik pęrli}

  @loop:
    mul EBX     {EDX:EAX = EBX * EAX}
    inc EBX     {EBX = EBX + 1}
    cmp EBX, X  {czy EBX = X}
    jle @loop    {if EBX<=x goto loop}

    {mov Result, EDX:EAX}
end;

Wg mnie wszystko powinno działać. Jednak problem pojawia się przy skoku warunkowym. Nigdy nie wykonuje się pętla po raz drugi. Nieważne co jest w EBX, a co w X. Nigdy się nie wykonuje. Jeśli zamiast X dam konkretną liczbę, to wtedy działa. O co tu chodzi?

[dopisane]
OK, okazało się, że na początku w EAX jest wartość X, więc wystarczy ją przenieść do innego rejestru - ja użyłem ECX. Ale dlaczego nie mogę tutaj bezpośrednio posługiwać się X?

Drugie pytanie, co zrobić, żeby zwrócić wartość EDX:EAX? Zakomentowany kod zwraca błąd kompilacji: Inline assembler syntax error

0

Ale dlaczego nie mogę tutaj bezpośrednio posługiwać się X?

Zobacz co ci assembler wygenerował. Pewnie wtedy będzie się dało powiedzieć co jest nie tak.

Drugie pytanie, co zrobić, żeby zwrócić wartość EDX:EAX? Zakomentowany kod zwraca błąd kompilacji: Inline assembler syntax error

Byś musiał zobaczyć w których rejestrach on podaje wynik i zrobić tak samo... może nawet żadna modyfikacja nie jest potrzebna.

1

Troche dokładniej zobaczyłem sprawę i wyszło mi tak (wszystko tyczy się Lazarusa x86):

  • FPC przełącza na tryb fastcall gdy używa się dyrektywy assembler więc X=EAX a ty to wcześniej zmieniłeś i stąd masz ten problem.
  • Jeżeli zrobisz bez tej dyrektywy, to kod działa.

Co do result to udało mi się to zrobić tak (x86):

mov dword [result],eax
mov dword [result-4],edx 

W sumie wyszło mi coś takiego:

function silnia_asm(x: integer): int64;assembler;
asm
  mov ecx,x
  mov EAX, 1    {Ustawiam EAX na 1 - pierwszy czynnik}
  mov EBX, 1    {i drugi czynnik - licznik pęrli}
  xor edx,edx


  @loop:
    mul EBX     {EDX:EAX = EBX * EAX}
    inc EBX     {EBX = EBX + 1}
    cmp EBX, ECX  {czy EBX = X}
    jle @loop    {if EBX<=x goto loop}

    mov dword [result],eax
    mov dword [result-4],edx
end;
0
-123 napisał(a):

Troche dokładniej zobaczyłem sprawę i wyszło mi tak (wszystko tyczy się Lazarusa x86):

  • FPC przełącza na tryb fastcall gdy używa się dyrektywy assembler więc X=EAX a ty to wcześniej zmieniłeś i stąd masz ten problem.
  • Jeżeli zrobisz bez tej dyrektywy, to kod działa.
    Rozumiem. Zapamiętam, dzięki

Co do result to udało mi się to zrobić tak (x86):

mov dword [result],eax
mov dword [result-4],edx 

No mi nie działa, inne wyniki zwraca. Ale w tym kierunku będę szedł, takie to proste, jak człowiek widzi ;) Dzięki!

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