News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Debugger disagreement

Started by Edward, April 12, 2009, 08:29:34 AM

Previous topic - Next topic

Edward

For some reason, when I run my program by executing it's .exe, it returns a wrong value, yet when I run through with debugger, it gives me the right value. What would cause such a thing?

BlackVortex

Does it throw any exceptions ? Maybe you have ignored exceptions in your debugger and excecution continues normally. Or maybe it's a timing error.

EDIT: OK, just noticed that I am posting in the 16-bit forum ! My post is probably irrelevant, unless you postted in the wrong forum. Is your question regarding DOS ?

FORTRANS

Hi,

   Well, the last time that bit me, it was that DEBUG sets up
the values in the registers at startup differently than the DOS
program loader.  Another time (on Windows XP) it was setting
the video mode differently (bad video drivers?).

HTH,

Steve N.

dedndave

i would like to see the stretch of code that's giving you trouble
only a few things are different with the 16 bit debugger
console display - of course, the debugger has to be visible
console input - it also has to receive input
the psp - in debug, the process is actually a child of the debugger
that can also affect the environment table
command line tail - mainly, a shorter length limitation due to the debug command
breakpoints - if you are applying a breakpoint - try adding a nop instruction or 2 to break on

Edward

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

;       Project 2 - Prooving NOR is universal for NOT, AND, and OR.
;       Written By Edward Benn

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

;   This program will go into various loops, crunching the values 0 - 255
;   through the logical operators and their NOR equivelence into a software LFSR.
;   By the end of the program, a byte code will be outputted from
;   the LFSR and this will be compared to the instructor's and other students
;   byte code outputted by their similar programs.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤


   
.model small

.stack 200h
   
.code

start:

; AL stores the current signature of the LFSR, BL contains the data to compress
; through the LFSR, and dl contains the loop counter.

main proc

   
NOTLOOP:

    mov      bl, dl                        ; moves the current count into bl
    not               bl                                  ; Nots current count value
    call               lfsr                                ; performs the lfsr on bl
   
    mov             bl, dl                            ; value to pass to lfsr
    or                bl, dl                            ; nor step 1 (or with self)
    not              bl                                   ; nor step 2 (negate the or)
    call               lfsr                                ; performs the lfsr on bh

    inc               dx                                  ; increments the current count value
    cmp          dx, 1                        ; number is max number to count to
    jl             NOTLOOP                        ; jump if number not met

    mov             cl, 8                               ; loop 8 times(8 bits)
   
PRINTLOOP:

    shl               al, 1                               ; shift al once
    jc                 PRINT1                              ; jump to print 1 if carry is set otherwise print 0

PRINT0:

    push   ax                 ; save ax
    mov      ah, 2                               ; print character interupt code
    mov      dl, '0'                             ; 0 character to be printed
    int        21h                                 ; msdos interupt handler
    jmp      DONEPRINT                           ; done printing
   

PRINT1:
   
    push       ax                           ; save ax
    mov          ah, 2                               ; print character interupt code
    mov          dl, '1'                             ; 1 character to be printed
    int            21h                                 ; msdos interupt handler

DONEPRINT:
   
   pop    ax                           ; get back the saved value

     loop    PRINTLOOP

   mov    ah, 4ch                        ; end program
   int      21h


main endp

; Takes the value in the AL register and runs it through the LFSR with the current
; value in bl

lfsr proc

    cmp      al, 0                           ; msb gets shifted
    jl                  MSBSET                          ; Jumps if the MSB of AL is set.
    shl              al, 1
    xor            al, bl                          ; xors the signature with the data
    jmp             LFSRDONE                        ; lfsr operation is complete, jump to done
   
MSBSET:
   
   shl       al, 1
    xor        al, bl                         ; xors the signature with the data
    xor        al, 01100011b               ; xors the signature with the lfsr feed back

LFSRDONE:
    ret
lfsr endp



end main

Edward

I think whats giving me the trouble is the LFSR proc.

When I run it through the debugger, i get the correct output 01100010, which means the lfsr works.

But when i run the program, I get something completely different.

sinsi

Your first code executed is "mov bl,dl" but DL isn't initialised. When you run it from debug, debug zeroes DX for you but DOS doesn't.
See also http://www.masm32.com/board/index.php?topic=10252.0
Light travels faster than sound, that's why some people seem bright until you hear them.

Edward

Wow thanks. I feel like such a n00b.  :clap:

dedndave

lfsr proc

    cmp      al, 0                           ; msb gets shifted
    jl                  MSBSET                          ; Jumps if the MSB of AL is set.
    shl              al, 1
    xor            al, bl                          ; xors the signature with the data
    jmp             LFSRDONE                        ; lfsr operation is complete, jump to done
   
MSBSET:
   
   shl       al, 1
    xor        al, bl                         ; xors the signature with the data
    xor        al, 01100011b               ; xors the signature with the lfsr feed back

LFSRDONE:
    ret
lfsr endp

Also, this subroutine is a little wacky.
When you write in assembler, your head has to always be looking for the most efficient way to accomplish
something, otherwise you are throwing out the main advantage of writing in assembler to begin with.
You will find this becomes more natural as you gain experience.
You will also find it very satisfying to know your head can manipulate bits like the CPU - lol.
This is the reason most of us that write assembly code prefer it over other languages.
It's not just the performance improvements, but the ego-boosting effects - lol.

One thing I see right away is that the CMP instruction is not needed
When you SHL on the AL register, bit 7 goes into the Carry Flag (CF).
You can use this fact to branch accordingly.

Also, you are duplicating the SHL and first XOR instructions.
Try to use the same one, regardless of the branch condition.

Another little flaw is that you JMP to a RET instruction - I usually avoid that, as you can replace the JMP with a RET.

The truth is, I always look at these simple pieces of code to see if I can eliminate branching altogether.
Conditional branches take a bit of time if the condition is true. Also, when the CPU branches to a new
address, it clears and re-loads the instruction queue, costing an additional penalty.
This can make code run faster, provided the math required does not outweigh the branch time.

I notice that the AH register is available for use (it has no assigned value in it that needs to be saved).
Here is a little trick you may enjoy. The CBW instruction takes the value in AL and sign-extends it into AX.
That means that if bit 7 of the AL register is 0, the CBW instruction will set AH to 00000000b.
If bit 7 of the AL register is 1, the CBW instruction will set AH to 11111111b.
We can use this to create a value in AH based on the condition of AL bit 7.

lfsr  PROC

      CBW
      AND ah,01100011b
      SHL al,1
      XOR al,bl
      XOR al,ah
      RET

lfsr  ENDP

The subroutine is now very small and fast. In fact, because it is only CALL'ed twice, it may
be advantageous to remove the CALL/RETurn altogether, and replace the CALL's with:

      CBW
      AND ah,01100011b
      SHL al,1
      XOR al,bl
      XOR al,ah

CALL and RET also take alot of cylces to execute. mainly because they represent
memory accesses when the return address is pushed and popped on the stack.
There is also the instruction queue thing, again.

This code still has a little room for imporvement:

      CBW
      AND ah,00110001b
      SHL ax,1
      XOR al,bl
      XOR al,ah

Here, we use bit 7 of the AL register to become the new bit 0 in the AH register.
I don't think this is much of an improvement in 32-bit world, but in 16-bit code,
this would make the code smaller by one byte, as SHL AX,1 is a single byte instruction.
SHL AL,1 is a two byte instruction. The optimization is still there if we use EAX.
In 32-bit code, I think the SHL EAX is one byte. I have yet to memorized the
32-bit instruction set - lol.

Both the NOTLOOP and the PRINTLOOP can be further optimized. I am going to leave that
to you, as 1) I want you to learn, and 2) I don't want to take all the fun out of it for you.

- Dave

Edward

Wow, that is really cool! It took me a few minutes to understand what was happening, but that is really clever!

Thanks for all the help guys!