简体   繁体   中英

Assembly (or NASM) annoying problem

I used to compile my asm code with TASM (on winXP) but I had some troubles so now I use NASM (on linux). This snippet shows what I'm trying to do:

(gdb) list 35
30      xor ecx,ecx             # ecx is a counter
31      mov bl, ' '             # this is what I'm looking for
32  count_spaces:
33      mov al,[esi]            # grab a char
34      jz  spaces_counted      # is this the end?
35      inc esi                 # next char
36      cmp al,bl               # found one?
37      jne count_spaces        # nope, loop
38      inc ecx                 # yep, inc counter
39      jmp count_spaces        # and loop

This looks correct to me, but :

Breakpoint 1, main () at project1.asm:30
30      xor ecx,ecx
(gdb) display (char) $al
1: (char) $al = 0 '\000'
(gdb) display (char) $bl
2: (char) $bl = 0 '\000'
(gdb) next
31      mov bl, ' '
2: (char) $bl = 0 '\000'
1: (char) $al = 0 '\000'
(gdb) 
count_spaces () at project1.asm:33
33      mov al,[esi]
2: (char) $bl = 0 '\000'
1: (char) $al = 0 '\000'
(gdb) 

I can't understand why al and bl didn't change.
I'm sure my code is correct, but.. I think I missed some NASM's option? BTW I compiled with

nasm -f elf -l project1.lst -o project1.o -i../include/ -g  project1.asm

After compiling, I disassembled the output and got:

 80483ec:   31 c9                   xor    %ecx,%ecx
 80483ee:   bb 20 00 00 00          mov    $0x20,%ebx

080483f3 <count_spaces>:
 80483f3:   8b 06                   mov    (%esi),%eax
 80483f5:   3d 00 00 00 00          cmp    $0x0,%eax
 80483fa:   74 0b                   je     8048407 <spaces_counted>
 80483fc:   46                      inc    %esi
 80483fd:   39 d8                   cmp    %ebx,%eax
 80483ff:   75 f2                   jne    80483f3 <count_spaces>
 8048401:   41                      inc    %ecx
 8048402:   e9 ec ff ff ff          jmp    80483f3 <count_spaces>

Note that GDB doesn't know about the 8 or 16 bit aliased registers. It will always print 0 for al, bl, ax, bx , etc. You should use eax, ebx , etc:

(gdb) info registers bl
Invalid register `bl'
(gdb) info registers bx
Invalid register `bx'
(gdb) info registers ebx
ebx            0xf7730ff4       -143454220
(gdb) p $bl
$1 = void
(gdb) p $bx
$2 = void
(gdb) p $ebx
$3 = -143454220
(gdb) p/x $bl
$4 = Value can't be converted to integer.
(gdb) p/x $bx
$5 = Value can't be converted to integer.
(gdb) p/x $ebx
$6 = 0xf7730ff4
(gdb) p (char) $bl
$7 = 0 '\0'
(gdb) p (char) $bx
$8 = 0 '\0'
(gdb) p (char) $ebx
$9 = -12 'ô'

Jester has the right answer , and deserves an up-vote.

But, I'd like to add something which is too long for a comment: you can teach gdb to display sub-registers if you wish, using the hook-stop hook , which runs just before any display happens, by adding the following to your .gdbinit file:

define hook-stop
set $bl=($ebx & 0xff)
set $bh=(($ebx & 0xff00) >> 8)
set $bx=($ebx & 0xffff)
end

(extend in the obvious way for other registers). display $bl etc. will then work as you expect.

I'm not sure if it's the problem you've noted, but I see one fairly obvious problem in your code. On the x86, a mov does not affect the flags. Your code:

33      mov al,[esi]            # grab a char
34      jz  spaces_counted      # is this the end?

Seems to assume that when you load al from [esi] that the z flag will be updated to reflect the content of al. That's not the case. To test whether the value you just loaded is zero, you need to add an explicit test:

mov al, [esi]
test al, al
jz spaces_counted

The value in the register should have changed before, but the flags should not have been updated to reflect the value.

As for whether nasm produced the right instructions, I'd disassemble the code to see what's really there. Right now, it's hard to guess whether the problem lies with nasm or with gdb. Of course, disassemblers aren't guaranteed to be bug-free either, but I'd be a bit surprised to see a problem with code this simple.

Flags are not modified by mov, so the jz at line 34 is not meaningful. If you follow the code from the initial xor , that is the only instruction that modifies the flags, so when the code reaches the jz at line 34 it just jumps (because the xor left it to zero). This does not explain the non-changing values of al or bl, but maybe some optimization took place that took into account the jz is always performed because of the xor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM