Coding and testing the procedure stack_to_string

In this post, I will write about how to create and nest for loops and how to use string instructions such as LODS and STOS in assembly language. As usual, I will write about how to debug the code in assembly language.

stack_to_string is the core procedure of AP-PROBE. Its task is to take the CPU registers saved on the stack, convert the nibbles into ASCII codes and save them inside a pre-formatted string. As every good turner has the drawing with him of the piece to be created and consults it before turning on the lathe, so I printed the program of AP-PROBE to have it nearby me and I started coding it up inside DEBUG.EXE (Fig. A). I started coding at 0x0120. At 0x0126 I couldn't know the location of the string, so I put 0xAABB knowing that I had to fix it later (red). In the same way, I didn't know where to points the two calls so I pointed them to themselves (red) keeping in mind that this is another point to fix later. Then I realized that I did a mistake starting at address 0x0140: I forgot to write the LOOP instruction there (red), so I stopped and restarted assembling at 0x0140 (Fig. A). Few lines later, I could immediately close the loops at 0x0140 and 0x0146 since those where pointing backwards to locations in memory that I could immediately see (green).

Best practice with DEBUG.EXE
Fig. A

Once the draft of the code was ready, I went on and fixed all addresses left undefined (in red Fig. A). I took note of the address of out_a_nibble (at 0x0220) and nibble_to_ASCII (at 0x0240) and I identified the beginning of the preformatted string. As you can see the pre-formatted string starts at 0x1521:0270. I had to transform this segmented address in a new segmented address to be stored in ES:[DI] (this is the destination of the STOSB instruction). What I did was to consider the segmented address and then use the command h within DEBUG.EXE to calculate the new segment (purple)1. I took the addition and used the command d to check that it was pointing exactly at the beginning of the pre-formatted string (dark red).

Best practice with DEBUG.EXE
Fig. B

Finally, I fixed the setup of the ES segment, with the one just calculated, as you can see in Fig. C.

Best practice with DEBUG.EXE
Fig. C

After that, I fixed the addresses of the 2 calls (Fig. D).

Best practice with DEBUG.EXE
Fig. D

In Fig. E I just fixed the last details and I got ready to test.

Best practice with DEBUG.EXE
Fig. E

In Fig. F you can see that the test was running fine and smooth. At the beginning I was tracing the code using the command t, towards the end I started proceeding the code using the command p. The reason was that I would find soon the CALLs and since I had tested the procedures already I didn't want to "trace inside" them.

Best practice with DEBUG.EXE
Fig. F

That was what happened, but something unexpected for me came together with this. In Fig. G you can see it. At the beginning using the command p was just fine. I have highlighted in green the parameters that the procedure needs together with its output. As you can see, I selected the high nibble in BX which was transferred in the low nibble of AL. At the same time, the procedure nibble_to_ASCII took the output of the previous procedure out_a_nibble as input to convert it into an ASCII code (yellow marked areas). So everything was fine until now and I was pretty happy about how the things were going. 2 lines later though something strange happened: the instruction LOOP affected many registers all together and the IP was pointing the instruction following the loop rather than pointing back at the beginning of the loop (all marked in red with a question mark).

Best practice with DEBUG.EXE
Fig. G

After some reading, I learned that p affects the entire loop. I thought that p starts executing code of a CALL terminating when a RET instruction was found. In reality p proceeds in all the conditions when is needed: LOOPS, REPs-Strings, CALL - RET and INT - IRET. If this was the case, then it should have transferred a complete register already. To check it I looked into memory with the command d. In fact, I saw in Fig. H that the first register was transferred completely.

Best practice with DEBUG.EXE
Fig. H

So I went on but this time I used t instead of p when I found the next LOOP instruction Fig. I.

Best practice with DEBUG.EXE
Fig. I

Since I was pretty confident that it was running fine, I decided to call the entire function using p to see the effects all together Fig. L.

Best practice with DEBUG.EXE
Fig. L

Test passed: the entire elements where converted and transferred from the stack to the pre-formatted string. Job done!



  1. The command h performs addition and subtraction of 2 number. As usual, within DEBUG.EXE all numbers (inputs, outputs, memory locations, etc) are hexadecimal. [click back]

<PREV.  -  ALL  -  NEXT>

Comments