mmap读写寄存器应注意不要越界

前两天使用/dev/mem来修改寄存器时遇到了一个问题. 当时的情况是这样的:
我有8K的寄存器空间需要访问, 但是当时我将mmap的空间大小写小了, 只写了1K, 相当于只映射了4K的空间. 但是当我操作到4K-8K的空间的时候, 读写看起来都没有问题, 读回来的数据和写入的数据是一致的. 但是实际寄存器上好像没有感受到一样(没有写入寄存器应有的现象), 刚开始一致怀疑是fpga的bitfile有问题. 后来无意发现了mmap指定的size不对, 改好了就可以了.
那么这里有一个问题, 为什么访问4K-8K的空间没有发生segment fault呢?

我做了一个实验, 下面有两个程序:
program 0 - have mmap:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

int main(int argc, char **argv)
{
int fd = open("a.txt", O_RDWR | O_DSYNC);
void *ptr = mmap(0, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("0x%016lx\n", (unsigned long)ptr);
pause();
}

program 1 - don’t have mmap:

1
2
3
4
5
6
7
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
pause();
}

先将程序运行起来, 然后通过/proc/[pid]/maps查看他们的线性地址分布情况:
对于program 0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
00400000-00401000 r-xp 00000000 fd:02 1051271                            /home/gngshn/b
00600000-00601000 r--p 00000000 fd:02 1051271 /home/gngshn/b
00601000-00602000 rw-p 00001000 fd:02 1051271 /home/gngshn/b
02293000-022b4000 rw-p 00000000 00:00 0 [heap]
7f17bd677000-7f17bd834000 r-xp 00000000 fd:00 924939 /usr/lib64/libc-2.24.so
7f17bd834000-7f17bda33000 ---p 001bd000 fd:00 924939 /usr/lib64/libc-2.24.so
7f17bda33000-7f17bda37000 r--p 001bc000 fd:00 924939 /usr/lib64/libc-2.24.so
7f17bda37000-7f17bda39000 rw-p 001c0000 fd:00 924939 /usr/lib64/libc-2.24.so
7f17bda39000-7f17bda3d000 rw-p 00000000 00:00 0
7f17bda3d000-7f17bda62000 r-xp 00000000 fd:00 924461 /usr/lib64/ld-2.24.so
7f17bdc3f000-7f17bdc41000 rw-p 00000000 00:00 0
7f17bdc5f000-7f17bdc60000 rw-s 00000000 fd:02 1066614 /home/gngshn/a.txt
7f17bdc60000-7f17bdc62000 rw-p 00000000 00:00 0
7f17bdc62000-7f17bdc63000 r--p 00025000 fd:00 924461 /usr/lib64/ld-2.24.so
7f17bdc63000-7f17bdc64000 rw-p 00026000 fd:00 924461 /usr/lib64/ld-2.24.so
7f17bdc64000-7f17bdc65000 rw-p 00000000 00:00 0
7fff75117000-7fff75138000 rw-p 00000000 00:00 0 [stack]
7fff75151000-7fff75153000 r--p 00000000 00:00 0 [vvar]
7fff75153000-7fff75155000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

对于program 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
00400000-00401000 r-xp 00000000 fd:02 1051230                            /home/gngshn/a
00600000-00601000 r--p 00000000 fd:02 1051230 /home/gngshn/a
00601000-00602000 rw-p 00001000 fd:02 1051230 /home/gngshn/a
7fb99a57a000-7fb99a737000 r-xp 00000000 fd:00 924939 /usr/lib64/libc-2.24.so
7fb99a737000-7fb99a936000 ---p 001bd000 fd:00 924939 /usr/lib64/libc-2.24.so
7fb99a936000-7fb99a93a000 r--p 001bc000 fd:00 924939 /usr/lib64/libc-2.24.so
7fb99a93a000-7fb99a93c000 rw-p 001c0000 fd:00 924939 /usr/lib64/libc-2.24.so
7fb99a93c000-7fb99a940000 rw-p 00000000 00:00 0
7fb99a940000-7fb99a965000 r-xp 00000000 fd:00 924461 /usr/lib64/ld-2.24.so
7fb99ab42000-7fb99ab44000 rw-p 00000000 00:00 0
7fb99ab63000-7fb99ab65000 rw-p 00000000 00:00 0
7fb99ab65000-7fb99ab66000 r--p 00025000 fd:00 924461 /usr/lib64/ld-2.24.so
7fb99ab66000-7fb99ab67000 rw-p 00026000 fd:00 924461 /usr/lib64/ld-2.24.so
7fb99ab67000-7fb99ab68000 rw-p 00000000 00:00 0
7ffdbcd07000-7ffdbcd28000 rw-p 00000000 00:00 0 [stack]
7ffdbcd31000-7ffdbcd33000 r--p 00000000 00:00 0 [vvar]
7ffdbcd33000-7ffdbcd35000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

可以看到program 0比program 1多了两段地址空间

  1. heap空间
  2. a.txt的mmap空间
    heap空间是引入标准io时, 内部使用引入的; a.txt的mmap空间是程序里面调用mmap产生的.
    这里可以看见mmap访问后面的地址没有出错的原因了, 在mmap后面刚好有一段mmap空间7f17bdc60000-7f17bdc62000 rw-p 00000000 00:00 0, size为8K, 权限为读写, 这段空间是匿名映射空间, 当时我的读写都操作到这里了.
    因此在使用mmap操作的时候, 一定要注意操作内存不要过界, 程序很可能不会因为你的操作过界而发生segment fault, 但是却会和你期望的相差甚远.