你能解释一下什么是程序断点以及在 x86-64 架构上的 Linux 中 sys_brk 调用返回什么。我曾经认为程序的断点是程序地址空间中最后一个有效地址。如果我想扩展它,我必须调用 brk syscall 并为其提供新的断点地址。如果成功,我会取回新的断点,它可能比请求的要大,因为 linux 是按页面操作的。但是我对一些简单代码的行为感到困惑。
.equ sys_call_exit,60 #rdi - exit code
.equ sys_call_brk, 12 #rdi - long break
.section .data
msg_brk:
.ascii "Your break is here:%d\n\0"
msg_addr:
.ascii "Addr: %d\n\0"
.equ ST_BRK1,8
.equ ST_BRK2,16
.equ ST_BRK3,24
.equ OFFSET, 65528
.globl _start
.section .text
_start:
movq %rsp,%rbp
subq $32,%rsp
################Get current brk
movq $sys_call_brk,%rax
movq $0,%rdi
syscall
movq %rax,ST_BRK1(%rbp)
###############################
################Try to extend
movq ST_BRK1(%rbp),%rdi
addq $8,%rdi
movq $sys_call_brk,%rax
syscall
movq %rax,ST_BRK2(%rbp)
##############################
################Get brk after extenstion
movq $sys_call_brk,%rax
movq $0,%rdi
syscall
movq %rax,ST_BRK3(%rbp)
###############################
#####print results#############
movq ST_BRK1(%rbp),%rsi
movq $msg_brk,%rdi
call printf
movq ST_BRK2(%rbp),%rsi
movq $msg_brk,%rdi
call printf
movq ST_BRK3(%rbp),%rsi
movq $msg_brk,%rdi
call printf
#########################3
# Get the last brk point in rbx
movq ST_BRK3(%rbp),%rbx
loop:
#Print rbx
movq %rbx,%rsi
movq $msg_addr,%rdi
call printf
#movq ST_BRK3(%rbp),%rbx
movb (%rbx),%cl
incq %rbx
jmp loop
movq $0,%rdi
call exit
首先,我得到了当前的 brk,然后我尝试将它扩展 8 个字节。然后我又得到了当前的 brk。之后,我尝试访问新 brk 上方的内存。结果如下:
Your break is here:22466560
Your break is here:22466568
Your break is here:22466568
......
Addr: 22470380
Addr: 22470381
Addr: 22470382
Addr: 22470383
Addr: 22470384
Segmentation fault (core dumped)
如您所见,首先我得到了 22466560 作为当前的 brk;然后 brk 完全按照要求移至 22466568 ;但是linux通常是按页面操作的,所以我又调用了一次brk(0)来检查真正的当前brk,我又得到了22466568。之后我尝试访问高于 22466568 的内存。我只在 22470385 上遇到分段错误。所以我可以访问 brk 上方的 3817 字节(22470385 - 22466568)。
我的问题是为什么我可以访问高于 brk 的内存以及如何获得真正的 brk 点?谢谢。