Memory GDB中的x86标签和LEA
我正在学习用x86汇编(目前为32位)编写代码,我正在努力完全理解内存模型。尤其令人困惑的是标签的语义、LEA指令和可执行文件的布局。我编写了这个示例程序,以便检查它在gdb中的运行情况Memory GDB中的x86标签和LEA,memory,assembly,gdb,x86,nasm,Memory,Assembly,Gdb,X86,Nasm,我正在学习用x86汇编(目前为32位)编写代码,我正在努力完全理解内存模型。尤其令人困惑的是标签的语义、LEA指令和可执行文件的布局。我编写了这个示例程序,以便检查它在gdb中的运行情况 ; mem.s SECTION .data msg: db "labeled string\n" db "unlabeled-string\n" nls: db 10,10,10,10,10,10,10,10 SECTION .text global _start _start:
; mem.s
SECTION .data
msg: db "labeled string\n"
db "unlabeled-string\n"
nls: db 10,10,10,10,10,10,10,10
SECTION .text
global _start
_start:
; inspect msg label, LEA instruction
mov eax, msg
mov eax, &msg
mov eax, [msg]
; lea eax, msg (invalid instruction)
lea eax, &msg
lea eax, [msg]
; populate array in BSS section
mov [arr], DWORD 1
mov [arr+4], DWORD 2
mov [arr+8], DWORD 3
mov [arr+12], DWORD 4
; trying to print the unlabeled string
mov eax, 4
mov ebx, 1
lea ecx, [msg+15]
int 80H
mov eax, 1 ; exit syscall
mov ebx, 0 ; return value
int 80H
SECTION .bss
arr: resw 16
我收集并链接了:
nasm -f elf -g -F stabs mem.s
ld -m elf_i386 -o mem mem.o
GDB会议:
(gdb) disas *_start
Dump of assembler code for function _start:
0x08048080 <+0>: mov $0x80490e4,%eax
0x08048085 <+5>: mov 0x80490e4,%eax
0x0804808a <+10>: mov 0x80490e4,%eax
0x0804808f <+15>: lea 0x80490e4,%eax
0x08048095 <+21>: lea 0x80490e4,%eax
0x0804809b <+27>: movl $0x1,0x8049110
0x080480a5 <+37>: movl $0x2,0x8049114
0x080480af <+47>: movl $0x3,0x8049118
0x080480b9 <+57>: movl $0x4,0x804911c
0x080480c3 <+67>: mov $0x4,%eax
0x080480c8 <+72>: mov $0x1,%ebx
0x080480cd <+77>: lea 0x80490f3,%ecx
0x080480d3 <+83>: int $0x80
0x080480d5 <+85>: mov $0x1,%eax
0x080480da <+90>: mov $0x0,%ebx
0x080480df <+95>: int $0x80
数组按预期填充了值1,2,3,4:
# before program execution:
(gdb) x/16w &arr
0x8049104 <arr>: 0 0 0 0
0x8049114: 0 0 0 0
0x8049124: 0 0 0 0
0x8049134: 0 0 0 0
# after program execution
(gdb) x/16w &arr
0x8049104 <arr>: 1 2 3 4
0x8049114: 0 0 0 0
0x8049124: 0 0 0 0
0x8049134: 0 0 0 0
程序执行前:
(gdb)x/16w和arr
0x8049104:0
0x8049114:0
0x8049124:0
0x8049134:0
#程序执行后
(gdb)x/16w和arr
0x8049104:1 2 3 4
0x8049114:0
0x8049124:0
0x8049134:0
我不明白为什么在gdb中打印标签会导致这两个值。另外,如何打印未标记的字符串。
提前感谢 < p>它有些混淆,因为GDB不理解标签的概念,实际上它是用来调试高级语言(C或C++)编写的程序,一般来说。因此,它试图将二进制中看到的内容映射到高级语言概念——变量和类型——基于对正在发生的事情的最佳猜测(在没有编译器的调试信息告诉它正在发生什么的情况下) nasm做什么 对于汇编器来说,标签是尚未设置的值——它实际上在链接器运行时获得其最终值。通常,标签用于引用内存段中的地址——实际地址将在链接器布局最终可执行映像时定义。汇编器生成重定位记录,以便使用链接器可以正确设置标签 所以当汇编程序看到
mov eax, msg
它知道msg
是与数据段中的地址相对应的标签,因此它生成一条指令将该地址加载到eax中
mov eax, [msg]
它生成一条指令,从msg
地址的内存中加载32位(寄存器eax的大小)。在这两种情况下,都会生成重新定位,以便链接器可以插入最终地址msg
(撇开它不谈——我不知道&
对nasm意味着什么——它没有出现在我能看到的文档中的任何地方,所以我很惊讶它没有给出错误。但它看起来像是将它作为[]
的别名对待)
现在LEA是一个有趣的指令——它的格式基本上与从内存中移出的指令相同,但它不读取内存,而是将本来读取的地址存储到目标寄存器中
lea eax, msg
毫无意义——源是标签(地址)msg
,它是一个(链接时间)常量,不在内存中的任何位置
lea eax, [msg]
有效,因为源在内存中,所以它会将源地址粘贴到eax中。这与mov eax,msg
的效果相同。最常见的情况是,您只会看到lea
与更复杂的寻址模式一起使用,这样您就可以利用x86 AGU进行有用的工作,而不仅仅是计算地址。例如:
lea eax, [ebx+4*ecx+32]
它在AGU中执行一个移位和两个加法,并将结果放入eax,而不是从该地址加载
gdb做什么
在gdb中,当您键入p
时,它会尝试对
进行评估,以尽可能理解C/C++编译器对该表达式的意义
(gdb) p msg
它查看msg
并说“这看起来像一个变量,所以让我们获取该变量的当前值并打印它。”“。现在它知道编译器喜欢将全局变量放入.data段,并为这些变量创建与变量同名的符号。由于它将符号表中的msg
视为.data
段中的一个符号,因此它假定这就是正在发生的事情,并获取该符号处的内存并打印它。现在它不知道这个变量是什么类型(没有调试信息),所以它猜测它是一个32位int,并以此打印它
因此,输出
$1 = 1700946284
是msg的前4个字节,被视为整数
对于p&msg
,它理解您想要获取变量msg
的地址,因此它直接从符号中给出地址。当打印地址时,gdb打印关于这些地址的类型信息,从而输出“数据变量,无调试信息”
如果需要,您可以使用强制转换来指定gdb的类型,它将使用该类型而不是猜测的类型:
(gdb) p (char)msg
$6 = 108 'l'
(gdb) p (char [10])msg
$7 = "labeled st"
(gdb) p (char *)&msg
$8 = 0x80490e4 "labeled string\\nunlabeled-string\\n\n\n\n\n\n\n\n\n" <Address 0x804910e out of bounds>
克里斯·多德经济特区
(旁白——我不知道&对nasm意味着什么——它没有出现在我能看到的文档中的任何地方,所以我很惊讶它没有给出一个错误。但它看起来像是把它当作[]的别名。) 哦,哦!你已经发现了秘密语法!很久以前,每个用户请求都向Nasm添加了“&”(作为“[]”的别名)。它从未被记录在案。也从未被移除过。我会坚持使用“[]”。由于“无文件记录”,它可能会消失。请注意,其含义几乎与它对gdb的含义“相反” 可以尝试使用“-F矮人”而不是“-F刺”。它应该是gdb使用的“本机”调试信息格式。(我自己从未注意到有多大的不同) 最好的 坦率的
我可以通过以下方式获得另一个值:
(gdb)p(int[])&msg
$1={134516964}
有没有办法用sys\u write系统调用打印未标记的字符串?我可以像这样打印未标记的字符串:(gdb)p(char*)(&msg)+16
$1=0x80490f4“未标记的字符串\\n\n\n\n\n\n\n
另一个值是msg的十进制地址(gdb)p/d&msg
$10=134516964
注意:sys\u write需要edx处字符串的长度,因此:mov edx,17
在int 80H
$1 = 1700946284
(gdb) p (char)msg
$6 = 108 'l'
(gdb) p (char [10])msg
$7 = "labeled st"
(gdb) p (char *)&msg
$8 = 0x80490e4 "labeled string\\nunlabeled-string\\n\n\n\n\n\n\n\n\n" <Address 0x804910e out of bounds>
mov ebx, 1 ; fd 1 (stdout)
lea ecx, [msg+15] ; address
mov edx, 17 ; length
write_more:
mov eax, 4 ; sys_write
int 80H ; write(1, &msg[15], 17)
test eax, eax ; check for error
js error ; error, eax = -ERRNO
add ecx, eax
sub edx, eax
jg write_more ; only part of the string was written