Search code examples
assemblyx86-64stack-memorymemory-segmentation

Will an implicit stack switch occur when switching from compatibility mode to 64-bit mode at the same privilege level?


When switching from compatibility mode to 64-bit mode at the same privilege level by a far call, fields such as BASE or LIMIT in segment registers are ignored, and 64-bit pointer registers are all available. However, if the BASE field is ignored, the stack base address will become 0x0 implicitly, which means an implicit stack switch will be raised, am I right? And if my understanding is correct, how does the CPU switch back to the original stack when returning via the ret instruction?


Solution

  • The SDM does use the term "implicit stack switch" to describe this behavior, but only when the call is performed using a call gate.

    ... when using a call gate to perform a far call to a segment at the same privilege level, an implicit stack switch occurs as a result of entering 64-bit mode. The SS selector is unchanged, but stack segment accesses use a segment base of 0x0, the limit is ignored, and the default stack size is 64 bits. The full value of RSP is used for the offset, of which the upper 32 bits are undefined.

    Although the SDM doesn't describe the behavior when the call is performed without using a call gate, the behavior I observe is the same. The return address (cs:rip) is pushed to the new stack (ignoring ss.base) and a far ret to return to the 32 bit code works. And of course the 32 bit code continues to use ss.base as usual.

    (In my test, the upper bits of RSP were 0 before entering compatibility mode, and remain 0 when performing the call back into 64-bit mode.)

    Here are memory dumps after running a program that does the following:
    ss.base = 0x80
    esp = 8385f118
    push 32323232
    push esp
    far call to 64-bit code (return address is 20:776bb1e2)
    push 64646464
    push rsp
    far call to 32-bit code (return address is 38:776bb208)
    push 30303030
    push esp
    add esp, 8
    far ret
    add rsp, 10
    far ret
    push 31313131
    push esp

    8385f0f0: 00000000 00000000 8385f100 00000000
    8385f100: 64646464 00000000 776bb1e2 00000020
    8385f110: 00000000 00000000 00000000 00000000
    8385f120: 00000000 00000000 00000000 00000000
    
    8385f160: 00000000 00000000 8385f0ec 30303030
    8385f170: 776bb208 00000038 00000000 00000000
    8385f180: 00000000 00000000 8385f10c 31313131
    8385f190: 8385f114 32323232 00000000 00000000