11

While learning assembly language from a book there is a listing showing some basic operations:

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

After assembling with "$yasm -f elf64 -g dwarf2 -l listing.lst listing.asm" command and linking with "$ld -o listing listing.o" I ran the program in gdb. There whenever I tried to print the value of a variable, gdb showed this error message:

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

Same for the other variable 'b'. However casting 'a' or 'b' for int worked:

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

But isn't this supposed to work without casting? Why do I need to cast? What mistake I've made in my source file?

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
Anik Samiur Rahman
  • 111
  • 1
  • 1
  • 6
  • 1
    `dq` is most likely NOT `int` on your target platform (I'm never sure from head on which target platform the `int` is 64b). So you are probably printing only 32 bit part of the value by the casting. (and I'm also not sure what type the gdb recognizes, does `p (int64_t)a` work, or you have to use base C types like `p (long long)a`? Or even some asm are recognized like `p (qword)a`?) – Ped7g Sep 10 '18 at 09:29
  • Thanks for noting that Ped7g. sizeof() returns 4 for int in my PC. So it should be dd. But changing dq to dd didn't cure the problem. – Anik Samiur Rahman Sep 10 '18 at 11:37
  • 1
    `mov rax,[a]` does read 8 bytes, so it should be then `mov eax,[a]` if you want to use only `dd` to define the data (or `movsx rax,dword [a]` in case you want sign-extend the 32 bit memory value into 64 bit `rax`). Also I don't see how `dq` vs `dd` would fix anything, it just changes amount of memory defined after label `a`. Giving label `a` some kind of type information in debug info is beyond what I usually do in assembly (you make me sort of recognize how the 8 bit era forced me so much to keep track of everything in head, that I didn't even think about debugger being aware of "type"). – Ped7g Sep 10 '18 at 11:59
  • I mean, for me your question is not even "problem", I simply always pick the correct size in debugger by myself for particular symbol. Now that you asked about it, yeah, it would be sort of nice if the assembler would provide more info about symbols for debugger. Then again usually when one needs assembler (very rarely), he often does need also non-conventional work with memory, so defining some kind of "type" for label `a` may get actually into your way (if you access that memory by different instructions, for example if you vectorize some code, accessing several elements at one time). – Ped7g Sep 10 '18 at 12:03
  • so *"But isn't this supposed to work without casting?"* - no, not on it's own. The debugger will do that when the particular label has attached also information about the expected "type" of data stored there, which high level languages often provide, because in C something like `int32_t a = 1;` does define 32 bit integer, but in assembly something like `a: dd 1` does define label pointing at next first byte of emitted machine code (the `a:` part of line), and then it defines four bytes `1, 0, 0, 0` (the `dd 1` part of line), they are like disconnected entities, you can even use two lines. – Ped7g Sep 10 '18 at 12:10

2 Answers2

3

But isn't this supposed to work without casting?

No. GDB tells you that it has no idea what type a and b are.

What mistake I've made in my source file?

You didn't make any mistakes, but you also didn't supply any debugging info that GDB could use.

You may have expected yasm -g dwarf2 ... to do so, but it only creates minimal debug info describing the source, nothing else:

$ 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)
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
3

Older GDB used to default to assuming that a symbol was an int when it didn't have debug info describing the size / type.

This generally cause more confusion than the current behaviour, so it was changed. e.g. The value displayed in Kdbg is wrong -- NASM

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • So having to specify variable type is not a bad thing after all. And its definitely not a bug, aye? PS: I'm using GDB version 8.1.0.20180409 – Anik Samiur Rahman Sep 11 '18 at 03:26
  • @AnikSamiurRahman: that's correct, this is the expected behaviour. The fact that NASM doesn't have syntax to create the necessary debug info could be considered a missing feature. Unlike MASM, there's no magical association between a label and a `dq` on the same line. Don't forget the `:` after a label name before the dq, to avoid ambiguity with instruction mnemonics. e.g. `bound: dq 1` is legal, but `bound dq 1` won't assemble because [`bound`](http://felixcloutier.com/x86/BOUND.html) is an instruction. There's zero advantage to using `a dq 1` instead of `a: dq 1` in NASM syntax. – Peter Cordes Sep 11 '18 at 03:30