GDB показывает сообщение об ошибке при попытке напечатать переменную в программе на ассемблере

При изучении языка ассемблера по книге есть листинг, показывающий некоторые основные операции:

segment .data
a   dq  176
b   dq  4097

segment .text
global _start

_start:
    mov rax, [a]    ; Move a into rax.
    add rax, [b]    ; add b o rax.
    xor rax, rax
    ret

После сборки с помощью команды "$yasm -f elf64 -g dwarf2 -l listing.lst listing.asm" и линковки с помощью "$ld -o listing listing.o" я запустил программу в gdb. Там всякий раз, когда я пытался напечатать значение переменной, gdb показывал это сообщение об ошибке:

(gdb) p a
'a' has unknown type; cast it to its declared type

То же самое для другой переменной «b». Однако кастинг «a» или «b» для int работал:

(gdb) p (int)a
$11 = 176
(gdb) p (int)b
$12 = 4097

Но разве это не должно работать без кастинга? Зачем мне кастинг? Какую ошибку я сделал в исходном файле?


person Anik Samiur Rahman    schedule 10.09.2018    source источник
comment
dq, скорее всего, НЕ int на вашей целевой платформе (я никогда не уверен, на какой целевой платформе int равен 64b). Таким образом, вы, вероятно, печатаете только 32-битную часть значения путем приведения. (и я также не уверен, какой тип распознает gdb, работает ли p (int64_t)a, или вам нужно использовать базовые типы C, такие как p (long long)a? Или даже некоторые asm распознаются, как p (qword)a?)   -  person Ped7g    schedule 10.09.2018
comment
Спасибо, что заметили, что Ped7g. sizeof() возвращает 4 для int на моем ПК. Так и должно быть дд. Но изменение dq на dd не решило проблему.   -  person Anik Samiur Rahman    schedule 10.09.2018
comment
mov rax,[a] считывает 8 байтов, поэтому должно быть mov eax,[a], если вы хотите использовать только dd для определения данных (или movsx rax,dword [a], если вы хотите расширить знаковое значение 32-битного значения памяти до 64-битного rax). Также я не вижу, как dq против dd что-то исправит, это просто изменяет объем памяти, определенный после метки a. Предоставление метке a какой-либо информации о типе в отладочной информации выходит за рамки того, что я обычно делаю в ассемблере (вы заставляете меня как бы понять, как 8-битная эра заставила меня так сильно отслеживать все в голове, что я даже не думал о том, что отладчик знает о типе).   -  person Ped7g    schedule 10.09.2018
comment
То есть для меня ваш вопрос даже не проблема, я просто всегда сам подбираю правильный размер в отладчике для конкретного символа. Теперь, когда вы спросили об этом, да, было бы неплохо, если бы ассемблер предоставил больше информации о символах для отладчика. Опять же, обычно, когда нужен ассемблер (очень редко), ему часто нужна и нетрадиционная работа с памятью, так что определение какого-то типа для метки a может оказаться на вашем пути (если вы обращаетесь к этой памяти другими инструкциями, для например, если вы векторизуете какой-то код, обращаясь к нескольким элементам одновременно).   -  person Ped7g    schedule 10.09.2018
comment
Итак, Но разве это не должно работать без приведения? - нет, не само по себе. Отладчик сделает это, когда конкретная метка также прикрепит информацию об ожидаемом типе хранящихся там данных, которую часто предоставляют языки высокого уровня, потому что в C что-то вроде int32_t a = 1; определяет 32-битное целое число, но в ассемблере что-то вроде a: dd 1 определяет метку указывает на следующий первый байт сгенерированного машинного кода (часть строки a:), а затем определяет четыре байта 1, 0, 0, 0 (часть строки dd 1), они подобны разъединенным объектам, вы даже можете использовать две строки.   -  person Ped7g    schedule 10.09.2018


Ответы (2)


Старый GDB по умолчанию предполагал, что символ был int, когда у него не было отладочной информации, описывающей размер/тип.

Обычно это вызывает больше путаницы, чем текущее поведение, поэтому оно было изменено. например Значение, отображаемое в Kdbg, неверно -- NASM

person Peter Cordes    schedule 10.09.2018
comment
Так что необходимость указывать тип переменной в конце концов не так уж и плоха. И это точно не баг, да? PS: я использую GDB версии 8.1.0.20180409. - person Anik Samiur Rahman; 11.09.2018
comment
@AnikSamiurRahman: это правильно, это ожидаемое поведение. Тот факт, что NASM не имеет синтаксиса для создания необходимой отладочной информации, можно считать отсутствующей функцией. В отличие от MASM, между меткой и dq в одной строке нет магической связи. Не забывайте : после имени метки перед dq, чтобы избежать двусмысленности с мнемоникой инструкций. например bound: dq 1 является допустимым, но bound dq 1 не будет собираться, поскольку bound — это инструкция. Нет никакого преимущества в использовании a dq 1 вместо a: dq 1 в синтаксисе NASM. - person Peter Cordes; 11.09.2018

Но разве это не должно работать без кастинга?

Нет. GDB говорит вам, что понятия не имеет, что такое тип a и b.

Какую ошибку я сделал в исходном файле?

Вы не допустили ошибок, но также не предоставили никакой отладочной информации, которую мог бы использовать GDB.

Возможно, вы ожидали, что yasm -g dwarf2 ... сделает это, но он создает только минимальную отладочную информацию, описывающую источник, и ничего больше:

$ readelf -wi listing.o

Contents of the .debug_info section:

  Compilation Unit @ offset 0x0:
   Length:        0x37 (32-bit)
   Version:       2
   Abbrev Offset: 0x0
   Pointer Size:  8
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <c>   DW_AT_stmt_list   : 0x0
    <10>   DW_AT_low_pc      : 0x0
    <18>   DW_AT_high_pc     : 0x14
    <20>   DW_AT_name        : listing.asm
    <28>   DW_AT_comp_dir    : /tmp/
    <2e>   DW_AT_producer    : yasm 1.3.0
    <39>   DW_AT_language    : 32769    (MIPS assembler)
person Employed Russian    schedule 10.09.2018