Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 为什么没有';当存储超过BSS的末尾时,是否会出现分段错误?_Linux_Assembly_X86_Segmentation Fault_Nasm - Fatal编程技术网

Linux 为什么没有';当存储超过BSS的末尾时,是否会出现分段错误?

Linux 为什么没有';当存储超过BSS的末尾时,是否会出现分段错误?,linux,assembly,x86,segmentation-fault,nasm,Linux,Assembly,X86,Segmentation Fault,Nasm,我正在试验汇编语言,并编写了一个程序,将2个硬编码字节打印到标准输出中。这是: section .text global _start _start: mov eax, 0x0A31 mov [val], eax mov eax, 4 mov ebx, 1 mov ecx, val mov edx, 2 int 0x80 mov eax, 1 int 0x80 segment .bss

我正在试验汇编语言,并编写了一个程序,将2个硬编码字节打印到标准输出中。这是:

section .text
     global _start

_start:
     mov eax, 0x0A31
     mov [val], eax
     mov eax, 4
     mov ebx, 1
     mov ecx, val
     mov edx, 2

     int 0x80

     mov eax, 1
     int 0x80

 segment .bss
     val resb 1;   <------ Here
section.text
全球启动
_开始:
mov-eax,0x0A31
mov[val],eax
mov-eax,4
mov-ebx,1
移动电子计算机,val
mov edx,2
int 0x80
mov-eax,1
int 0x80
第2部分:bss

val-resb-1 与大多数其他现代体系结构一样,x86在x86上使用(同样与许多其他体系结构一样),粒度为4KB

val
的4字节存储不会出错,除非链接器碰巧将其放置在页面的最后3个字节,并且下一个页面未映射

实际情况是,您只需覆盖
val
之后的内容。在这种情况下,它只是页面末尾未使用的空间。如果您在BSS中有其他静态存储位置,您将使用它们的值。(如果您愿意,可以称之为“变量”,但“变量”的高级概念不仅仅意味着内存位置,变量可以存在于寄存器中,并且不需要地址。)


除了上面链接的维基百科文章外,另请参见:

  • (页表格式的内部结构,以及操作系统如何管理和CPU如何读取)

但实际上将2个字节(charcode代表1和换行符)放入内存位置

mov[val],eax
是一个4字节的存储。操作数大小由寄存器决定。如果要进行2字节存储,请使用
mov[val],ax

有趣的事实:MASM会在操作数大小不匹配时发出警告或出错,因为它会根据在其后面保留空间的声明,将大小与符号名神奇地关联起来。NASM不会妨碍您,因此,如果您编写了
mov[val],0x0A31
,这将是一个错误。这两个操作数都不表示大小,因此需要
mov-dword[val],0x0A31
(或
word
byte


val
放在页面末尾以获取segfault 由于某种原因,BSS在32位二进制文件中不会从页面的开头开始,但它接近页面的开头。您没有链接到任何其他将占用BSS中大部分页面的内容
nm bss no SEGFULT
显示它位于
0x080490a8
,4k页面是
0x1000
字节,因此bss映射中的最后一个字节将是
0x08049fff

当我向
.text
部分添加指令时,BSS开始地址似乎会发生变化,因此这里链接器的选择可能与将内容打包到ELF可执行文件有关。这没有多大意义,因为BSS没有存储在文件中,它只是一个基址+长度。我不会去兔子洞;我确信将
.text
稍微增大会导致BSS从页面的开头开始,这是有原因的,但我不知道它是什么

无论如何,如果我们构造BSS使
val
正好位于页面末尾之前,我们可能会得到一个错误:

... same .text

section .bss
dummy:  resb 4096 - 0xa8 - 2
val:    resb 1

;; could have done this instead of making up constants
;; ALIGN 4096
;; dummy2: resb 4094
;; val2:   resb
然后构建并运行:

$ asm-link -m32 bss-no-segfault.asm
+ yasm -felf32 -Worphan-labels -gdwarf2 bss-no-segfault.asm
+ ld -melf_i386 -o bss-no-segfault bss-no-segfault.o

peter@volta:~/src/SO$ nm bss-no-segfault
080490a7 B __bss_start
080490a8 b dummy
080490a7 B _edata
0804a000 B _end         <---------  End of the BSS
08048080 T _start
08049ffe b val          <---------  Address of val

 gdb ./bss-no-segfault

 (gdb) b _start
 (gdb) r
 (gdb) set disassembly-flavor intel
 (gdb) layout reg

 (gdb) p &val
 $2 = (<data variable, no debug info> *) 0x8049ffe
 (gdb) si    # and press return to repeat a couple times
关键事项:
rwxp
表示读/写/执行和私有。即使在第一条指令之前就停止了,不知何故它已经“脏”(即写入)。文本段也是如此,但这是gdb将指令更改为
int3
所期望的


08049000-0804a000(以及映射的
4KB
大小)向我们显示,BSS只有一个页面被映射。没有数据段,只有文本和BSS。

听起来像是未定义的行为保存了您的字节,因为保留字节后仍有内存映射。在普通计算机上,页面粒度为4096字节。@St.Antario否,在考虑整个环境(硬件和操作系统)时,它的定义很好。如果在
val:
之前添加
resb 4094
,它会崩溃吗?(4094+1=4095,因此对于assembler+linker,它看起来仍然只值一个页面,但是4字节写入应该访问另一个页面)。同样,出于某种奇怪的原因(链接器脚本/etc),在这种情况下,您的可执行文件可能已经保留了2+个页面,因此无法保证崩溃(您可以使用类似
objdump
或链接器的映射文件来检查二进制的元数据,为特定部分设置了多少空间)@Ped7g:原来BSS不一定从一页的开头开始。请参阅我的答案更新,了解如何执行您的建议
nm
是检查符号地址最有用的工具。它听起来可能很奇怪,但我想感谢您对出现分段错误的解释:)。我使用
nasm
并使用
-elf64
选项编译源代码。bss段从页面的开头开始
0000000000 601000
。放置一些虚拟内容后,我得到了
0000000000 601ffa b val
。然后是
mov[val]rax
segfault。这取决于虚拟大小,bss段可能从开头开始,也可能不从开头开始。如果
dummy db 0xFFE
0000000000 6000db\u bss\u启动
。如果
dummy db 0xFFA
0000000000 601000 B\uuu bss\u启动
。你能解释一下吗?那个汇编器/链接器是特定的吗?编译并链接如下
nasm-f elf64 segfult.asm ld segfault.o
@St.Antario:在64位代码中,除非您已经阅读并理解,否则不要使用
int 0x80
接口。我假设是32位代码,因为您使用的是32位ABI(它会截断所有内容,包括指向32位的指针)。@St.Antario:我假设您的意思是
dummy resb 0xFFE
db
将一个字节组合到输出中,并且无论如何都不能在BSS中放入非零值。我注意到BSS开始作为一个页面的开始,甚至不仅仅是在
.text
部分添加
mov[val],ax
的奇怪之处。如果你好奇的话,你应该问一个新问题,我不知道
... the r-x private mapping for .text
08049000-0804a000 rwxp 00000000 00:15 2885598                            /home/peter/src/SO/bss-no-segfault
Size:                  4 kB
Rss:                   4 kB
Pss:                   4 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         4 kB
Referenced:            4 kB
Anonymous:             4 kB
...
[vvar] and [vdso] pages exported by the kernel for fast gettimeofday / getpid