我正在阅读一本关于 x64 汇编的书。这本书描述了一些关于如何使用 gdb 的内容,我能够检查整数,但打印不起作用。 如果我通过像这样使用检查来包含诸如“db”之类的大小,则检查将适用于整数,
x/bu &bNum
这将按预期输出 123。
对于浮点值,如果我在检查浮点值之前没有检查整数,我会得到我认为不正确的结果。 运行
x/qf &qNum3
将输出结果 1.26443839e+11
如果我使用
x/bu &bNum
然后运行x/qf &qNum3
它将给出预期结果 3.1400000000000001
那么为什么只有在检查整数之后检查浮点数才能给出正确的输出?
使用前面任何不带“&”符号的命令都会导致 gdb 响应 “‘qNum3’具有未知类型;将其转换为其声明的类型” 这是预期的反应吗?
打印似乎永远不会给出正确的结果。
我按照书中的指示使用下面的命令来汇编和链接程序
nasm -f elf64 -g -F dwarf move.asm -l move.lst
gcc -o move move.o -no-pie
这是书上给出的示例程序。
; move.asm
section .data
bNum db 123
wNum dw 12345
dNum dd 1234567890
qNum1 dq 1234567890123456789
qNum2 dq 123456
qNum3 dq 3.14
section .bss
section .text
global main
main:
push rbp
mov rbp,rsp
mov rax, -1 ; fill rax with 1s
mov al, byte [bNum] ; does NOT clear upper bits of rax
xor rax,rax ; clear rax
mov al, byte [bNum] ; now rax has the correct value
mov rax, -1 ; fill rax with 1s
mov ax, word [wNum] ; does NOT clear upper bits of rax
xor rax,rax ; clear rax
mov ax, word [wNum] ; now rax has the correct value
mov rax, -1 ; fill rax with 1s
mov eax, dword [dNum] ; does clear upper bits of rax
mov rax, -1 ; fill rax with 1s
mov rax, qword [qNum1] ; does clear upper bits of rax
mov qword [qNum2], rax ; one operand always a register
mov rax, 123456 ; source operand an immediate value
movq xmm0, [qNum3] ; instruction for floating point
mov rsp,rbp
pop rbp
ret
x/qf &qNum3
预计接近3.14
x/qf &qNum3
将输出结果“<0x404027> 1.26443839e+11”
x/qt &qNum3
预计接近 01000000 01001000 11110101 11000011
x/qt &qNum3
将输出结果 01010001 11101011 10000101 00011111
x/qx &qNum3
预计接近 0x4048F5C3
x/qx &qNum3
将输出结果 0x51eb851f
print /f &qNum3
预计接近3.14
print /f &qNum3
将输出“$2 = 2.0803755547161745e-317”
如果首先运行命令
x/bu &bNum
,之前的检查命令现在将输出与之前不同的结果。
命令
x/qf &qNum3
将输出预期结果 3.14
x/qt &qNum3
现在将输出结果 00011111
x/qx &qNum3
现在将输出结果 0x1f
/q
不是 GDB 的大小修饰符。根据 h x
,8 字节大小为 /g
(巨型)。
x /gf &qNum3
正确地将内存检查为8字节双精度,p (double)qNum3
或 p (double[3])qNum1
一样打印全部 3 个。
我不知道
/q
作为 /x 的修饰符做什么,但由于大小仍然是默认的 32 位,您将尾数的低 4 个字节解释为 float
(IEEE 二进制 32) ,与您从 p (float)qNum3
获得的数字相同