Почему GDB не показывает мне изменение в массиве BSS, когда я вычисляю адрес с тем же выражением, что и режим адресации?

Написал простую программу с большим буфером в .bss сегменте

h_vals:
    resq 99999

затем попытался увеличить значение некоторой ячейки массива.

mov rcx, [h_vals+8*rax]
inc rcx
mov [h_vals+8*rax], rcx

По-прежнему в gdb вижу одно и то же значение (0) как до, так и после выполнения третьей инструкции.

x/dg &h_vals &h_vals + 8 * $rax
0x6d68c0: 0

Почему я все еще вижу 0, когда пытаюсь проверить адрес, по которому я сохранен?


person Bulat M.    schedule 04.09.2016    source источник


Ответы (1)


mov явно перемещает данные; В случае сбоя ваша программа перестанет работать.

Размер по умолчанию для символов без отладочной информации составляет 4 байта. Вы можете использовать ptype h_vals, чтобы проверить, что об этом думает gdb.

Помните, что синтаксис gdb работает как C, даже если вы отлаживаете asm. В C добавление чего-либо к указателю смещает такое количество элементов, а не столько байтов.

&h_vals &h_vals + 8 * $rax не выполняет оценку в GDB по адресу, который вы ожидаете. (Кроме того, я думаю, что &h_vals &h_vals - это опечатка, а не то, что вы на самом деле использовали.)

Так как gdb считает, что &h_vals является int*, &h_vals + offset создаст байтовое смещение 4 * смещение, точно так же, как h_vals[offset] в C. Таким образом, адрес, который вы examining в gdb, на самом деле [h_vals + 8 * 4 * rax].

Другой способ проверки: p /x &h_vals и p /x $rax по отдельности. Вы можете вычислить сами и сравнить с адресом, который вы видели в выходных данных x/.


Самым безопасным решением здесь является преобразование в char*:

x /dg  8 * $rax + (char*)&h_vals

Или: определите свои символы в .c, чтобы компилятор сгенерировал для них отладочную информацию (потому что вы не хотите делать это вручную).

например поместите unsigned long h_vals[99999]; в .c, который вы компилируете с gcc -c -g vars.c, и свяжите полученный .o с .o, созданным YASM из вашего .asm.

person Peter Cordes    schedule 04.09.2016
comment
ptype h_val type = ‹переменная данных, без отладочной информации› print & h_vals type = ‹переменная данных, без отладочной информации› 0x6010c0 print $ rax 27328 Не согласуется с 27328 * 8 = 218624 (0x35600), 0x35600 + 0x6010c0 = 0x6366c0 (not 0x6d68c0). - person Bulat M.; 04.09.2016
comment
вы можете использовать p /x $rax для печати в шестнадцатеричном формате. Похоже, что размер по умолчанию для символов без отладочной информации составляет 4 байта; что точно соответствует: (0x6d68c0 - 0x6010c0 ) / (8 * 27328) равно 4. - person Peter Cordes; 04.09.2016
comment
rax - это 0x6aco (27328 в десятичной системе). Расчеты такие же. - person Bulat M.; 04.09.2016
comment
По сути, теперь расчеты совпадают с показателями GDB. Можно ли добавить отладочную информацию в буфер в разделе .bss, чтобы gdb подумал, что символ в нем имеет байтовую длину, чтобы можно было не преобразовывать в char *? ptype h_val показывает <data variable, no debug info> - person Bulat M.; 04.09.2016
comment
Да, отладочную информацию можно вручную создать так же, как ее генерируют компиляторы, но я думаю, что это больше проблем, чем пользы. Посмотрите когда-нибудь на gcc -g -S вывод, на все дополнительные директивы, которые определяют метаданные отладки. Вероятно, самый простой способ сделать это - заставить компилятор сделать это за вас: определить unsigned long h_vals[99999]; в .c, который вы компилируете (gcc -c -g vars.c), и связать полученный .o с .o, созданным YASM из вашего .asm. - person Peter Cordes; 04.09.2016
comment
Да, я скомпилировал файл с unsigned long h_vals_2[99999], и после связывания со сборкой он отображается в gdb как type = unsigned long [99999], спасибо. Информация об отладке в .s действительно огромна, и ее не очень приятно создавать вручную. - person Bulat M.; 04.09.2016