空指针是在计算机的哪个级别定义的?
原始计算机基本上只有物理地址从 0 开始的内存,对吧?然后有人可以编写汇编代码(例如 BIOS)并实际上将值设置为 0。
现在,如果有启动计算机的 BIOS,那么有人可以为操作系统编写加载程序。该人可以决定用汇编语言将实际值移动到内存中的位置 0 吗?
如果他们使用 C 或 C++ 怎么办?他们可以有一个值为 0 的指针并用它来访问第一个内存位置吗?这是否需要专门适配的编译器?
然后操作系统就登场了。它有一个内存管理器,由malloc
调用以获取更多内存。是否可以编写一个操作系统,它可以简单地使用空指针作为普通指针,但在其他方面的行为与 Linux 完全相同,然后如果有人使用普通的、未修改的 GCC 编译 C 程序,空指针不会导致分段过错?
A raw computer basically just has memory with physical addresses starting at 0, right? Then someone could write assembly code (such as a BIOS) and actually put a value at 0.
Now if there is a BIOS that starts the computer, then someone could write a loader for an operating system. Can that person decide to move actual values to position 0 in the memory in assembly language?
What if they use C or C++? Can they have a pointer with value 0 and use it to access the first memory location? Does that need a specially adapted compiler?
And then the operating system enters the scene. It has a memory manager which is called by malloc
to get more memory. Could an operating system be written which can simply use null pointers as normal pointers, but otherwise behaves exactly like Linux, and then if someone compiles a C program with a normal, unmodified GCC for it, a null pointer wouldn't lead to a segmentation fault?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
C 和类似语言中的空指针只是一种约定,以便轻松检查指针未指向任何有效内容的指示。计算机中没有任何东西可以物理地阻止任何东西在内存位置 0 处存储数据。事实上,C 标准甚至没有规定空指针的所有位必须为零或对应于内存位置 0,只是它必须是你从
(void *)0
得到什么。malloc
和类似函数不能返回空指针作为有效的内存位置,因为空指针的返回是专门定义来指示失败的。现在,为了支持 C 中空指针的这种极其常见的用法,一些操作系统将专门不映射或以其他方式为与空指针对应的内存位置设置陷阱,因此任何意外访问都会立即引发分段违规等。当然,确实存在不这样做的操作系统。
The null pointer in C and similar languages is just a convention, to allow an easy to check for indication that a pointer doesn't point to anything valid. There is nothing in the computer that physically stops anything from storing data at memory location 0. In fact, the C standard doesn't even state that the null pointer must have all bits zero or correspond to memory location 0, just that it must be what you get from
(void *)0
.malloc
and similar functions cannot return a null pointer as a valid memory location, because a return of a null pointer is specifically defined to indicate failure.Now, to support this extremely common usage of the null pointer in C, some operating systems will specifically not map or otherwise set a trap for the memory location corresponding to the null pointer so any accidental accesses will immediately raise a segmentation violation or the like. Operating systems do exist that do not do this, of course.
虽然 NULL 指针在 C 源代码中表示为
0
,但并不要求底层位模式实际上必须为 0。它只需与非 NULL 指针。有一些架构的例子,其底层不为零。C 实现本身决定了 NULL 是什么。
您还应该意识到,现代操作系统(好吧,那些使用虚拟内存的操作系统)在进程虚拟地址空间和底层物理内存之间存在脱节。
While the NULL pointer is represented in C source code as a
0
, there is no requirement that the underlying bit pattern actually has to be 0. It just has to be distinguishable from non-NULL pointers. There are examples of architectures where it isn't zero under the covers.It's the C implementation itself that decides what a NULL is.
You should also realise that modern operating systems (well, those that do virtual memory) have a disconnect between a process virtual address space and the underlying physical memory.
阅读此 为什么 Linux 程序会取消引用(char*)0 并不总是出现段错误? 它至少是您响应的一半:-)
而这个 http://wiki.debian.org/mmap_min_addr 第一部分,关于其中的漏洞可能在“修复” mmap_min_addr 之前。而这个http://eparis.livejournal.com/606.html,有一个故事该漏洞。
所以是的,可以将页面映射到地址 0 并在那里放置代码。您的系统对程序中的错误的抵抗力会变弱,但“完美”的程序将像以前一样工作。至于“如果程序访问段 0 会发生什么”这个问题......好吧......无论你想要什么......
但我认为你并没有完全理解“现代”处理器的受保护内存是如何工作的。每个进程都可以看到映射到某个地址的不同内存块,有些进程可以“写入”该页,有些只能“读”(有些可以执行)。
Read this Why does Linux program that derefrences (char*)0 not always segfault? it's at least half of your response :-)
And this http://wiki.debian.org/mmap_min_addr The first part, about the vulnerabilities that where possible before the "fixing" of mmap_min_addr. And this http://eparis.livejournal.com/606.html, with a story of the vulnerability.
So yes, it's possible to map a page to address 0 and put code there. Your system will be weaker to errors in programs, but "perfect" programs will work in the same way as before. As for the question "what would happen if a program access the segment 0"... Well... Whatever you want...
But I think you don't exactly comprehend how the protected memory of "modern" processors work. Each process can see a different block of memory mapped to an address, and some processes can "write" to this page, and some can only "read" (and some can execute).
Linux(或任何“正常”进程和虚拟内存操作系统)保留最低地址未映射,特别是为了检测空指针错误。考虑以下示例:
这适用于 selinux 之前的系统(打印“x”),尽管在我的禁用了 selinux 的桌面上,它只能以 root 身份工作,不能以普通用户身份工作。但关键是您通常可以控制虚拟地址空间中的所有内容。如果你真的想把一些东西放在 0 处,你可以,尽管你可能会遇到,例如,拒绝处理 0 处字符串的代码。
Linux (or any "normal" processes and virtual-memory OS) leaves the lowest addresses unmapped, specifically to gain detection of null-pointer bugs. consider the following example:
this works on pre-selinux systems (prints "x"), though on my desktop with selinux disabled, it only works as root, not a normal user. but the point is that you generally have control of everything in your virtual address space. if you really want to put something at 0, you can, though you might run into, for instance, code that refuses to deal with a string at 0.