1

The code must output 'ccb',but output only 'c', LOOP is done only one time, i have calibrated in TD, but why LOOP is done only one time?

I THINK THAT I MUST TO DECREMENT STRING_LENGTH, SO I WROTE

DEC STRING_LENGTH

BUT IT NOT WORK, SO I WROTE LIKE THAT

MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP

I KNOW WHAT ARE YOU THINKING RIGHT NOW, THAT IS SO INCORRECT, YOU ARE RIGHT)))

I CAN USE C++, BUT I WANT TO DO IT ONLY IN ASSEMBLY,

DOSSEG
.MODEL SMALL
.STACK 200H
.DATA
STRING DB 'cScbd$'
STRING_LENGTH EQU $-STRING
STRING1 DB STRING_LENGTH DUP (?) , '$'
.CODE
MOV AX,@DATA
MOV DS,AX
XOR SI,SI
XOR DI,DI

MOV CX,STRING_LENGTH

S:

MOV BL,STRING[DI]
AND STRING[DI],01111100B
CMP STRING[DI],01100000B
JNE L1
MOV AL,BL
MOV STRING1[SI],AL
ADD SI,2
L1:

ADD DI,2

LOOP S

MOV DL,STRING1
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
END
Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • 1
    More likely your loop doesn't do what you think it does. You aren't clobbering CX inside the loop, so it should run `STRING_LENGTH` times. Use your debugger to single-step and see what you end up with in memory. What do you want your loop to do, anyway? And why are you destroying the original `STRING`? – Peter Cordes Jun 06 '18 at 23:09
  • I used debuger to single-step and see that in line MOV CX,STRING-LENGTH //CX IS 0006 after LOOP S //CX IS 0000 but why? – Levon Muradyan Jun 06 '18 at 23:22
  • Because you looped 6 times. [How exactly does the x86 LOOP instruction work?](https://stackoverflow.com/q/46881279) – Peter Cordes Jun 06 '18 at 23:24
  • But in debuger dont looped 6 times,looped only 1 time – Levon Muradyan Jun 06 '18 at 23:26
  • Then you're using your debugger wrong. Are you sure you're hitting the single-step button, rather than set-until-higher-address or something? Even if the branch target of the `loop` instruction was itself, instead of where `S:` is in the source, that would only decrement `CX` by 1. It's not possible for one execution of `loop` to change CX from 6 to 0. – Peter Cordes Jun 06 '18 at 23:29
  • After first looping in CX must be 0005,but in CX after first looping is 0000,why? – Levon Muradyan Jun 06 '18 at 23:30
  • I used F8 in DOSBOX,there is written ''F8-STEP'' – Levon Muradyan Jun 06 '18 at 23:31
  • **That's impossible**. Are you sure you didn't just set a breakpoint after the loop or something? Post a [mcve] of exactly what you did with your debugger if you want help figuring out what's going on with it. – Peter Cordes Jun 06 '18 at 23:32
  • I am sure that after loop there is not any breakpoint – Levon Muradyan Jun 06 '18 at 23:36
  • in loop position // ax 4663,bx F463,cx 0006,dx F58A,si 0002,di 0002,bp 0100,sp 0200,ds 4658,es 4644,ss 4659,cs 4654,ip 0028 one step after loop // only changes cx 0000,si 000A,di 000C,ip 002A – Levon Muradyan Jun 06 '18 at 23:46
  • The step *definitely* ran more tha 1 instruction. All those register changes match with the loop running 6 times; your debugger just isn't showing it. You're running TurboDebugger inside DOSBOX, right? So you're not using [DOSBOX's built-in debugger](https://www.vogons.org/viewtopic.php?t=3944). I haven't used TD so IDK why it's not stopping at each instruction. Google on that, maybe you'll find something. – Peter Cordes Jun 06 '18 at 23:54
  • It means that loop work 6 times,but why outputs only 'c' in place 'ccb'? – Levon Muradyan Jun 07 '18 at 00:05
  • maybe outputs algorithm is wrong? – Levon Muradyan Jun 07 '18 at 00:06
  • `MOV DL,STRING1` is obviously wrong. That's a load from memory of one byte, but `int 21h/ah=9` takes a pointer in DX. http://spike.scu.edu.au/~barry/interrupts.html#ah09. It's probably just random chance that it prints anything at all. Use your debugger to examine memory and see what DX points to, and also check that your loop filtered into STRING1 correctly. – Peter Cordes Jun 07 '18 at 00:16
  • 1
    In Turbo Debugger (TD.EXE) the "F8 step" will "execute" the `loop` instruction completely (`cx` many times, or more, if the code will modify `cx` meanwhile). Use the "F7 trace" option to go from cx=6 to cx=5. (upvoted because you are trying to debug, keep communicating after posting question, and the TD UI is somewhat tricky in this particular case, but otherwise you have still a lot of work ahead of you). – Ped7g Jun 07 '18 at 06:16
  • 1
    Inside the loop when it writes to string1, it writes one byte, but increments si by 2. – prl Jun 07 '18 at 06:21
  • 1
    The loop iterates 6 times and increments di by 2 each time, so it goes way past the end of the input string, overwriting as it goes. – prl Jun 07 '18 at 06:24

1 Answers1

5

In Turbo Debugger (TD.EXE) the F8 "F8 step" will execute the loop completely, until the cx becomes zero (you can even create infinite loop by updating cx back to some value, preventing it from reaching the 1 -> 0 step).

To get "single-step" out of the loop instruction, use the F7 "F7 trace" - that will cause the cx to go from 6 to 5, and the code pointer will follow the jump back on the start of the loop.


About some other issues of your code:

MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP

sp is not general purpose register, don't use it for calculation like this. Whenever some instruction does use stack implicitly (push, pop, call, ret, ...), the values are being written and read in memory area addressed by the ss:sp register pair, so by manipulating the sp value you are modifying the current "stack".

Also in 16 bit x86 real mode all the interrupts (keyboard, timer, ...), when they occur, the current state of flag register and code address is stored into stack, before giving the control to the interrupt handler code, which usually will push additional values to the stack, so whatever is in memory on addresses below current ss:sp is not safe in 16 bit x86 real mode, and the memory content keeps "randomly" changing there by all the interrupts being executed meanwhile (the TD.EXE itself does use part of this stack memory after every single step).

For arithmetic use other registers, not sp. Once you will know enough about "stack", you will understand what kind of sp manipulation is common and why (like sub sp,40 at beginning of function which needs additional "local" memory space), and how to restore stack back into expected state.


One more thing about that:

MOV SP,STRING_LENGTH
DEC SP
MOV STRING_LENGTH,SP

The STRING_LENGTH is defined by EQU, which makes it compile time constant, and only compile time. It's not "variable" (memory allocation), contrary to the things like someLabel dw 1345, which cause the assembler to emit two bytes with values 0100_0001B, 0000_0101B (when read as 16 bit word in little-endian way, that's value 1345 encoded), and the first byte address has symbolic name someLabel, which can be used in further instructions, like dec word ptr [someLabel] to decrement that value in memory from 1345 to 1344 during runtime.

But EQU is different, it assigns the symbol STRING_LENGTH final value, like 14.

So your code can be read as:

mov sp,14   ; makes almost sense, (practically destroys stack setup)
dec sp      ; still valid
mov 14,sp   ; doesn't make any sense, constant can't be destination for MOV
Ped7g
  • 16,236
  • 3
  • 26
  • 63