Сборка (или NASM) досадная проблема
Раньше я компилировал свой asm-код с помощью TASM (на winXP), но у меня были некоторые проблемы, поэтому теперь я использую NASM (на linux). Этот фрагмент показывает, что я пытаюсь сделать:
(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
Мне это кажется правильным, но :
Breakpoint 1, main () at project1.asm:30
30 xor ecx,ecx
(gdb) display (char) $al
1: (char) $al = 0 '00'
(gdb) display (char) $bl
2: (char) $bl = 0 '00'
(gdb) next
31 mov bl, ' '
2: (char) $bl = 0 '00'
1: (char) $al = 0 '00'
(gdb)
count_spaces () at project1.asm:33
33 mov al,[esi]
2: (char) $bl = 0 '00'
1: (char) $al = 0 '00'
(gdb)
Я не могу понять, почему
al и bl не изменились.Я уверен, что мой код является правильным, но.. Я думаю, что пропустил какой-то вариант NASM?
Кстати, я скомпилировал с
nasm -f elf -l project1.lst -o project1.o -i../include/ -g project1.asm
После компиляции я разобрал выходные данные и получил:
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>
4 ответов:
Обратите внимание, что GDB не знает о 8 или 16 битных псевдонимных регистрах. Он всегда будет печатать 0 для
al, bl, ax, bxи т. д. Вы должны использовать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 'ô'
У Шута есть правильный ответ , и он заслуживает права голоса.
Но, я хотел бы добавить кое-что, что слишком длинно для комментария: вы можете научить
gdbотображать подрегистраторы, если хотите, используяhook-stopХук , который запускается непосредственно перед любымdisplayслучаем, добавив следующее в ваш файл.gdbinit:define hook-stop set $bl=($ebx & 0xff) set $bh=(($ebx & 0xff00) >> 8) set $bx=($ebx & 0xffff) end(расширить очевидным образом для других регистров).
display $blи т. д. тогда будет работать так, как вы ожидаете.
Я не уверен, что это та проблема, которую вы отметили, но я вижу одну довольно очевидную проблему в вашем коде. На x86 a
movне влияет на флаги. Ваш код:33 mov al,[esi] # grab a char 34 jz spaces_counted # is this the end?, по-видимому, предполагает, что при загрузке
alиз[esi]флагzбудет обновлен, чтобы отразить содержимое al. Это не случай. Чтобы проверить, является ли только что загруженное значение нулевым, необходимо добавить явный тест:mov al, [esi] test al, al jz spaces_countedЗначение в регистре должно было измениться до этого, но флаги должны не быть обновлены, чтобы отразить значение.
Что касается того, производил ли nasm правильные инструкции, я бы разбирал код, чтобы увидеть, что там на самом деле. Сейчас трудно сказать, в чем проблема-в nasm или в gdb. Конечно, дизассемблеры также не гарантируют отсутствие ошибок, но я был бы немного удивлен, увидев проблему с таким простым кодом.
Флаги не модифицируются mov, поэтому jz в строке 34 не имеет смысла. Если вы следуете коду от начального
xor, это единственная инструкция, которая изменяет флаги, поэтому, когда код достигает jz в строке 34, он просто прыгает (потому чтоxorоставил его равным нулю). Это не объясняет неизменность значений al или bl, но, возможно, имела место некоторая оптимизация, которая учитывала, что jz всегда выполняется из-за xor.
Comments