Kłopot z przepisaniem stringu w pętli i zapis po znaku do pamięci.

0

Cześć. Proszę nie przenosić nigdzie tego wątku, bo tutaj podejrzewam wiecej osób spojrzy. A rozwiązanie jest pewnie banalne, ale ja go nie znam. I dlatego, jak rzadko się mi to zdarza, muszę popytać. Problem dotyczy dosowego TSR'a uruchamianego pod DosBOX'em.

Wcześniej wygooglowałem taki kod i on działa ok:

model small
 .386 

.data
greeting db 'Hello There!'
greeting_len = ($-greeting)

.code

main PROC
mov ax,@data
mov ds,ax 
mov ecx,greeting_len
lea si, greeting

start_loop:

  mov dl, [si]
  inc si
  mov ah,6
  int 21h

loop start_loop

mov ah,4ch
int 21h

main ENDP
END main

Jednak ja chciałbym w swoim TSR'ze działającym na przerwaniu 16h przepisać zawartość zmiennej po znaku do pamięci. Normalnie robiłem tak, że porównywałem co trzeba. Oto wycinek:

        mov     esi,6E8BCh
        cmp     byte ptr ds:[si+0],56h
        je      Step1
        jmp     MagicPatch
Step1:
        cmp     byte ptr ds:[si+1],49h
        je      Step2
        jmp     MagicPatch
Step2:
        cmp     byte ptr ds:[si+2],4Bh
        je      Step3
        jmp     MagicPatch
Step3:
        mov     byte ptr ds:[si+00],50h
        mov     byte ptr ds:[si+01],52h
        mov     byte ptr ds:[si+02],45h

Jednak takich bajtów po mov jest mnóstwo i chciałem to sobie uprościć stosując zmienne z tekstem i wpisać w ten sposób do pamięci po jednym znaku w kolejne miejsca. Kombinuję tak, jak poniżej. Ale gra, w której pamięci kombinuje z takim kodem się wiesza. Bez niego jest ok. Prosiłbym o podpowiedź jak to poprawić. Wycinek kodu:

mov ebx, 6E8BCh
greeting db 'OLESIO'
greeting_len = ($-greeting)
mov ecx, greeting_len
lea si, greeting
start_loop:
  mov dl, [si]
  mov byte ptr ds:[ebx], dl
  inc si
  inc bx
loop start_loop

Użyłem innych rejestrów, bo gdzieś musiałem dodatkowo wcisnąć adres początkowy do zmiany. Jak to zrobić żeby działalo bez zawieszania, bo kompiluje się bez warningów czy errorów? TSR kompilowany pod TASMem, jako plik wynikowy *.com. Z góry dziękuję za wszelkie przykłady kodu z rozwiązaniem problemu.

0

Nie no to co wstawiłeś to horror :D Przeciez asembler nie odróżnia KODU od DANYCH. Jak masz coś takiego:

mov ebx, 6E8BCh
greeting db 'OLESIO'
greeting_len = ($-greeting)
mov ecx, greeting_len

To on spróbuje WYKONAĆ te twoje bajty 'OLESIO' interpretując to jako instrukcje. Nie dziwie się że się zawiesza :D
Dane muszą być deklarowane gdzieś gdzie nigdy nie stanie instruction pointer.

edit: możesz wykonać takie ćwiczenie myślowe, zamień ten swój napis oraz jego długość na liczbową reprezentację bajtów a następnie z tablicą opcodów sprawdź jak zostały one "zinterpretowane" przez procesor kiedy je napotkał ;)

Prosty fix:

mov ebx, 6E8BCh
jmp instrukcje
greeting db 'OLESIO'
greeting_len = ($-greeting)
instrukcje:
mov ecx, greeting_len
0

@Shalom: dziękuję za odpowiedź. Ponieważ kompilator się nie pluł, a ja wolałem mieć wszystko w jednym miejscu, wklejając tutaj. Pomyślałem - nie wiem dlaczego, że zmienne mogą być w dowolnym miejscu. A przecież wiadomo, że zamieniło mi to na opcody. Mogłem spojrzeć pod HIEW na skompilowanego com'a, to bym wszystko wiedział. Teraz dałem na koniec tam gdzie jest u mnie reszta "stało-zmiennych" db i gra się nie wiesza.

Niemniej jednak pozostaje pytanie jak zrobić prawidłową pętlę żeby ze stringa pchnąc wszystko do pamięci. Zauważyłem, że nie można dawać mov byte ptr ds:[eax], dl ani ax. To dlatego, że ten rejestr to akumulator? Prosił bym o przykład pętli, założmy, że adres początkowy mamy w esi i chcemy wpisać od niego zwiększając co jeden pod ds:[esi] kolejne znaki z jakiejś zmiennej, na przykład grettings. Ponieważ aktualnie nie zachodzi zmiana w pamięci gry. Gdzie wiele operacji mov po sobie działa. Jednak jak wiadomo chćę uniknąć takiego "potworka".

EDIT: Mam na końcu kodu gdzie reszta zmiennych to:

chr1 db 0
greeting db 'TEST'
greeting_len = ($-greeting)

I próbowałem tak, ale wiesza grę w momencie gdy powinna nastąpić podmianka tekstu w pamięci na mój własny:

mov ebx,6E8BCh
mov ecx,greeting_len
lea si, greeting
start_loop:
  mov dl, [si]
  mov byte ptr ds:[bx],dl
  inc si
loop start_loop

Próbowałem też tak, ale w żądanym miejscu znak jest niewidoczny a dump pamięci dla testów wykazal, że zamiast znaku "T" ze zmiennej jest tam znak o kodzie ASCII (szesnastkowym) OF. Coś pewnie robię nie tak, z tym chr1 to kombinowałem ponieważ podobny sposób zadziałal w moim TSR to Larryego 2. Tam to zdalo egzamin, ale kopiowałem z jednego miejsca pamięci do innej lokalizacji pamięci. I stosowałem aż osiem zmiennych, bo inaczej nie umialem.

mov esi,6E8BCh
mov ecx,greeting_len
lea bx,greeting
PatchLoop:
  mov al,[bx]
  mov chr1,al
  mov bl,chr1
  mov byte ptr ds:[si],al
  inc si
  inc bx
cmp si,cx
jb PatchLoop

Prosil bym o pomoc. Do ASM'a nie ma za wiele przykładów na Google z tym co chicałbym zrobić. A bawię się tutaj w bardzo zapomnianą tematykę jak DOS i TSR'y. I trochę muszę błądzić po omacku. Jak się uporam to już na przyszłość zostawię sobie kod i będę wiedział, jak kombinować :) Poza tym to dział Newbie, więc niski poziom metytoryczny i lamietnie chyba trochę mogą być ;)

0

@_13th_Dragon: prosił bym o konkretniejszy przykład takiej pętli pod TASM'a. Bo żeby w ogóle skompilowało się mi do com'a bez parametru /3 To zrobiłem tak - zmienne:

greeting db 'TEST+'
greeting_len = ($-greeting)

I później robię tak, ale gra się wiesza. Nie wiem jak to poprawić. Pętle nie są moją mocną stroną pod TASM'em.

      mov edi,6E8BCh
      mov si,offset greeting
      mov cx,greeting_len
      L1:
      lodsb
      mov     byte ptr ds:[di],al
      cmp al,'+'
      jne   increase
      stosw
      jmp L1
increase:
      inc eax
      inc edi
      stosb
      loop L1

Ponieważ na tej strone, którą podałeś jest mnóstwo przykładów i zmian, ale to głownie pod kątem MASM'a. Prosił bym więc o przykład kodu dla TASM, dla plików kompilowanych do *.com. Z góry dziękuję za cierpliwość oraz wyrozumiałość :)

0
      push es
      push ???
      pop es ; es dla tego twego obszaru
      mov edi,6E8BCh
      mov esi,offset greeting ; upewnić się że ds ma odpowiednią wartość
      mov ecx,greeting_len
      cld
      rep movsb ; cx razy kopiuj es:edi -> ds:esi
      pop es
0

Kurcze motam się. Nie umiem zrobić tak żeby gra się mi nie wieszała, bo nie wiem co powinienem dać tym drugim Pushem. Może wkleje tutaj jak wygląda u mnie od początku procka TSR'a przechwytująca przerwanie 16h. Aktualnie gra wywala DosBOX'a. Dodam, że pod labelem MagicPath jest dalsza część kodu, która wykonuje się później po podmianie tekstów w tak zwanym antypirackim docs checku w jednej ze starych dosowych gier. I ona działa ok, tylko że wcześniej kombinuje z tą pętlą i albo wiesza się przy pierwszym wywołaniu int 16h przez grę (wybór języka na początku) albo w momencie gdy pojawić ma się ten tak zwany docs check. Prosił bym o naprowadzenie z przykładem kodu, jak to poprawić by było prawidłowo. Dziękuję :)

TSRProc:
        push    bp
        mov     bp,sp
        add     bp,2
        pusha
        push    es
        push    ds
        push    word ptr ss:[bp+2]      ;CS
        pop     ax
        add     ax,02000h               ;AX+????=DS
        mov     ds,ax                   ;AX=DS
        mov     esi,6E8BCh
        cmp     byte ptr ds:[si+0],56h
        je      Step1
        jmp     MagicPatch
Step1:
        cmp     byte ptr ds:[si+1],49h
        je      Step2
        jmp     MagicPatch
Step2:
        cmp     byte ptr ds:[si+2],4Bh
        je      Step3
        jmp     MagicPatch
Step3:
      push es
      push ds
      pop es
      mov edi,6E8BCh
      mov si,offset greeting
      mov ecx,greeting_len
      cld
      rep movsb
      pop es
0
  1. Do porównania użyj: http://faydoc.tripod.com/cpu/cmpsb.htm
  2. push es już zrobiłeś na początku, nie potrzebujesz tego jeszcze raz pod Step3:
  3. jeżeli jesteś pewien że segment dla 6E8BCh jest ten sam to zrób: mov es,ax po: mov ds,ax
  4. Po rep movsb sprawdź czy tobie się zapisało to co trzeba tam gdzie trzeba.
  5. Czy dobrze rozumiem że sprawdzasz czy jest tam wpisane "VIK", jeżeli tak to podmieniasz napis?
0

Hint ode mnie, o którym już pewnie kiedys pisałem. emu8086 jest niezastąpione do testowania kodów asemblerowych :)

0
_13th_Dragon napisał(a):

Do porównania użyj: http://faydoc.tripod.com/cpu/cmpsb.htm

To może później, jeśli to ogarne, czy tymczasowo nie moga być cmp, jak teraz? Wolał bym się skupić na razie na w końcu działającej pętli.

push es już zrobiłeś na początku, nie potrzebujesz tego jeszcze raz pod Step3:

Teraz mam tak jak pokazuje w kodzie na końcu tego posta (fragment) i gra się wiesza przy wywołaniu 16h.

jeżeli jesteś pewien że segment dla 6E8BCh jest ten sam to zrób: mov es,ax po: mov ds,ax

Tak zrobiłem, tylko muszę używać niekiedy cx zamiast ecx jak poniżej, bo inaczej mam błąd o konieczności użycia przełacznika /3, bo inacze jest błąd że dyrektywa potrzebuje overdrive na linijce z ecx.

Po rep movsb sprawdź czy tobie się zapisało to co trzeba tam gdzie trzeba.

Pomimo zawieszenia na początku gry przy wyborze jednego z trzech języków. Robiąc dump pamięci pod Debuggerem DosBOX'a do pliku binarnego. Dla zmiennej o treści TEST mam w prawidłowym miejscu takie bajty 00 18 0F 00. Czyli nie to, co być powinno.

Czy dobrze rozumiem że sprawdzasz czy jest tam wpisane "VIK", jeżeli tak to podmieniasz napis?

Tak. Dokładnie to ma działać tak. Jeżeli te 3 kolejne bajty to będą litery VIK to ma podstawić w żadane miejsce tekst ze zmiennej żeby nie robić potworka z kilkudziesięciioma mov i bajt pod dany ds:[esi].

TSRProc:
        push    bp
        mov     bp,sp
        add     bp,2
        pusha
        push    es
        push    ds
        push    word ptr ss:[bp+2]      ;CS
        pop     ax
        add     ax,02000h               ;AX+????=DS
        mov     ds,ax                   ;AX=DS

      mov es,ax

        mov     esi,6E8BCh
        cmp     byte ptr ds:[si+0],56h
        je      Step1
        jmp     MagicPatch
Step1:
        cmp     byte ptr ds:[si+1],49h
        je      Step2
        jmp     MagicPatch
Step2:
        cmp     byte ptr ds:[si+2],4Bh
        je      Step3
        jmp     MagicPatch
Step3:
      mov edi,6E8BCh
      mov esi,offset greeting
      mov cx,greeting_len
      cld
      rep movsb
      pop es

@Shalom, dziekuję za sugestię. Ale ja przekompilowuje TASMem źródlo pod DosBOX'em robiąc po tym polecenie DOS pause, żeby upewnić się jakie były ewentualne błedy. Jeżeli nie ma to od razu odpalam grę i testuje "na żywca" :)

0
        push    bp
        mov     bp,sp
        add     bp,2
        pusha
        push    es
        push    ds
        push    word ptr ss:[bp+2]      ;CS
        pop     ax
        add     ax,02000h             ; nie podobają mi się te kombinacje !
        mov     ds,ax                   ;AX=DS
        mov     es,ax
        mov     edi,6E8BCh
        mov     esi,offset VIK
        mov     ecx,3
        cld
        rep      cmpsb
        jne       MagicPatch
        mov      edi,6E8BCh
        mov      esi,offset greeting
        mov      cx,greeting_len
        rep      movsb
        pop      ds
        pop      es
        ...
1

Nie podobają mi się te 32-bitowe offsety. Przecież limit selektorów w trybie rzeczywistym i tak jest domyślnie ustawiony na FFFFh.
Czy te odwołania w ogóle tobie działają?

0

Może @Azarien ma racje i należy działać wyłącznie w trybie 16 bitowym czyli

  • di
  • si
  • cx
0

Niestety porównywanie musiałem zrobić tak jak wcześnej swoją metodą, bo z Twoją gra się wieszała na samym starcie. Natomaist dodawanie do ax, które się Tobie nie podoba, z moich doświadczeń było koniecznie. Ponieważ inaczej dane do modyfikacji lądowały w złym miejscu pamięci gry i patch nie działał, jak zamierzałem. Wracając do pętli kombinowałem na różne sposoby i wstawiałem "żywcem" to co poleciłeś. I albo musiałem kompilować z parametrem /3, bo się mi czepaił jak coś pozmieniałem. Albo nie było zmian tekstu w ogóle.

@_13th_Dragon: i tutaj prośba plus pytanie. Czy mogę wysłać Tobie na prywatną wiadomośc kod TSR'a z jakim kombinuje wraz ze skonfigurowanym DosBOX'em w wersji z debuggerem i samą grą? Oraz objaśnić jak przetestować czy na pewno w pamięci ustaliła się potrzebna wartość? Zależy mi żeby możłiwie TSR był w pliku .com oraz nie było błędów typu zwiechy i "No stack" przy konieczności kompilacji z użyciem parametru "/3". Może mając żywy obiekt w posiadaniu dasz radę poprawić kod.

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