Reputation: 22979
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>
Upvotes: 4
Views: 1618
Reputation: 46998
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.
Upvotes: 5
Reputation: 58762
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 'ô'
Upvotes: 5
Reputation: 29021
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.
Upvotes: 1
Reputation: 490128
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.
Upvotes: 2