Search code examples
assemblycpu-architecturey86

why 0xfffffffc is an invalid address to access?


Hi I was reading an textbook,it says that programs are not allowed to access addresses greater than 0xc0000000 (as is the case for 32-bit versions of Linux), so below assembly code is invalid:

1. irmovl $1,%eax
2. xorl %esp,%esp // Set stack pointer to 0 and CC to 100
3. pushl %eax    // Attempt to write to 0xfffffffc, will fail

I'm confused. and I have two questions:

  1. why programs are not allowed to access addresses greater than 0xc0000000, isn't that address like 0xc0000008 a valid address?

  2. if programs are really not allowed to access addresses greater than 0xc0000000, 0xfffffffc is lower(less) than 0xc0000000, so why it will fail?


Solution

    1. why programs are not allowed to access addresses greater than 0xc0000000, isn't that address like 0xc0000008 a valid address?

    Modern operating systems leverage features of the hardware to prevent running applications from interfering with each other. The primary components of this isolation are privilege separation and virtual memory.

    Virtual memory (as opposed to physical memory) means that the addresses accessed by code (e.g. a mov instruction) aren't actual addresses of RAM. Instead, the memory management unit (MMU) leverages the page tables to translate virtual addresses (VA) to physical addresses (PA) before sending them out to RAM.

    Privilege separation is enforced by the CPU (and MMU), and is what allows for a single operating system kernel to have total control of the hardware, while safely running multiple user applications.

    Putting these two concepts together, typically the kernel runs in one region of virtual memory (inaccessible to userspace), and userspace processes run in another part.

    In the x86 32-bit arch port of the Linux kernel, a 1-3 split is often used, to provide 1 GB of VA space to the kernel, leaving 3 GB of VA space for each user application. Thus:

    • 0x00000000 - 0xBFFFFFFF : Userspace
    • 0xC0000000 - 0xFFFFFFFF : Kernel
    1. if programs are really not allowed to access addresses greater than 0xc0000000, 0xfffffffc is lower(less) than 0xc0000000, so why it will fail?

    There's a big difference between how data is represented (e.g. in a hardware register or in memory) and how it is interpreted (e.g. signed/unsigned integer, floating point number, text string, image, etc.)

    Note that if you interpret 0xFFFFFFFF as a 32-bit two's-compliment (signed) integer, you get -1. If you interpret it as an unsigned integer, you get (2^32 - 1) = 4294967295.

    Addresses are always unsigned; very generally speaking, there are no negative numbers when it gets down to the hardware.

    0xFFFFFFFC is greater than 0xC0000000. Thus, here it is a kernel address, and any userspace application that tries to access it will fault and be delivered a SIGSEGV signal.