Calling a procedure that exists in another code segment

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Hello,

For Intel systems:

If you call a procedure that exists in the same code segment in which the calling procedure exists, the hardware will push the instruction pointer for the next instruction after the call instruction on the top of the stack using whatever segment you have currently designated as the stack segment.

But, if you call a procedure that exists in another code segment, will the hardware push the entire far pointer on the stack like it would a near pointer?

That is, will the hardware automatically push both the segment selector for the calling procedure's segment and the offset within that segment for the next instruction after the call instruction on the top of the stack?

Thanks.
 
Last edited:

HumblePie

Lifer
Oct 30, 2000
14,667
440
126
All your recent questions seem like you are looking up exam answers. Could you at least put them all in the same thread?
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
All your recent questions seem like you are looking up exam answers. Could you at least put them all in the same thread?

*sigh*.......

For the last time, I'm not a formal student, I'm not doing homework, and I'm not taking or studying for an exam.

Forget it.....

Maybe I should just ask the types of questions that everyone else asks here:

"Hey guys, what type of sound card works best with the kind of speakers I have?" or whatever.......
 

Chaotic42

Lifer
Jun 15, 2001
33,929
1,098
126
*sigh*.......

For the last time, I'm not a formal student, I'm not doing homework, and I'm not taking or studying for an exam.

Forget it.....

Maybe I should just ask the types of questions that everyone else asks here:

"Hey guys, what type of sound card works best with the kind of speakers I have?" or whatever.......

I'm happy to see your threads here, honestly. You ask fairly deep questions and they're not about widgets and JS frameworks and such. Unfortunately I don't remember enough from my x86 Assembly class to be of any help on this one.
 
Reactions: Ken g6

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
I'm happy to see your threads here, honestly. You ask fairly deep questions and they're not about widgets and JS frameworks and such.

Thanks, I appreciate the positivity.

Unfortunately I don't remember enough from my x86 Assembly class to be of any help on this one.

It's OK.

I found the answer in Intel's manual; the answer is yes.

I guess I jumped the gun by posting the question.

Through, now I do have another related question.

But, I'll hold off for now.
 
Last edited:

exdeath

Lifer
Jan 29, 2004
13,679
10
81
That's not really done in modern times in user land. You'd only see those kinds of calls in DOS extenders with flat mode 32 bit programs with full exclusive access or in kernel code.

Certainly not at user mode now days. Other than mov segment over rides to FS:[0] to get your thread info block linear address workout needing to syscall.

But yes opcode 9A loads both the selector and offset. You'd commonly see this when task switching from kernel to user if I recall:

Current CS = 0x0008 CPL 0
User selector is 0x001B

CALL 0x001B:00040000

This is a inter privilege call that involves CPL0 to RPL3 and succeeds but not the other way back. You need to syscall or interrupt gate from CPL3 to RPL0.

You have to swap SS:ESP as well, that's what call gates and task states are all about, it can take care of loading all registers and swapping stacks atomically.

Even setting up protected mode in a bootloader though or even just a bare metal single task system (eg from DOS):

; GDT and IDT already set up

cli
lgdt [gdt]
lidt [idt]
mov eax, cr0
or eax,1
mov cr0, eax
jmp 0x08:reload_cs ; dummy far jump to load CS to actually enter pmode
reload_cs:
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
mov gs, ax
mov fs, ax
sti

; weeeee
 
Last edited:

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
That's not really done in modern times in user land........ Certainly not at user mode now days.

Why not?

What's so far fetched about calling out to a procedure in a different code segment?

Why doesn't anyone do that anymore?
 

exdeath

Lifer
Jan 29, 2004
13,679
10
81
Why not?

What's so far fetched about calling out to a procedure in a different code segment?

Why doesn't anyone do that anymore?

Because there is only one user mode execute segment descriptor and you don't have GDT access? The only time a far call, aka a CS code selector load, is used is to change privilege level on x86 and you are never doing that in an application in a protected multitasking OS.

Your only 2 code/execute descriptors valid for CS are going to be identical except one is DPL0 (selected by 0x0008) and one is DPL3 (selected by 0x001B) (in 32 bit versions both Windows and Linux I believe). Trying to load 0008 from 001B is going to be a general protection fault (current privilege level 3 trying to elevate to requested privilege level 0 check will fail when the MMU attempts to load the descriptor and sees PL0). Any as every mainstream OS only typically defines the two execute segment descriptors, any attempt to use anything but those two defined selectors for CS values will result in accessing a invalid or null descriptor and also cause a GPF.

The segmentation feature of descriptors has basically long been disabled and ignored by having base 0 limit max on all descriptors. In addition there is universal R/W/X enabled in descriptors for the entire memory limit and finer granularity over RWX is now deferred to the page tables post DEP/AMD64 improvements.

There is effectively one global RWX segment and the only thing really left that the selector controls at that point is setting CPL 0 or 3 when switching between kernel mode and user mode, so it's easy to see that the idea of far calls from a application or normal programmer perspective in pmode/lmode essentially don't exist. As a OS programmer? You do it every time you change tasks at the very least.

In fact the only reason selectors and segmentation exist is x86 legacy as protected mode, and privilege controls are also part of the descriptors, that's it.

There is however an OS called Multics that exists that is built around a segmentation model natively that would fully utilize the x86 segmentation model having multiple segments referenced with multiple different selectors and you can far call and selector swap for days. If you are intrigued by the segmentation model of x86 give it a look.

But the majority of systems in use today favor flat memory with paging as the advantages it offers with handling fragmentation and disk swap are significant and its disadvantages are easily nullified via hardware (MMUs, TLBs).
 
Last edited:

Mike64

Platinum Member
Apr 22, 2011
2,108
101
91
All your recent questions seem like you are looking up exam answers. Could you at least put them all in the same thread?
That would have to be longest time period allowed for a take-home exam I've ever seen...
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Because there is only one user mode execute segment descriptor

OK. I don't know anything about programming really.

But, you're saying that if in assembly I try to use the .code or .text (depending on the assembler being used) marker in more than one place, the assembler throws an error?

That is, you're not allowed to give a program more than one code segment?

and you don't have GDT access?

Why not?

What's stopping me from coding:

jmp "segment selector":"offset"

where segment selector is some 16 bit value that reaches into the GDT and grabs a code segment?

Why can't I do that?

As long as the dpl for the called upon descriptor is the same or greater than the cpl I don't see a problem.

The only time a far call, aka a CS code selector load, is used is to change privilege level on x86 and you are never doing that in an application in a protected multitasking OS.

What does the OS have to do with anything?

Doesn't the hardware stop this from happening by looking at the pertinent privilege levels?

Any OS restrictions should just be icing on the cake, right?

So, if you want to change privilege levels, you need to pass through a gate.

But what about frameworks and dynamically linked libraries?

Why can't I write some code that expects there to exist, already in the computer's memory, some preexisting code that my code calls out to?

Why can't I call out to some preexisting library at run-time (I believe this is called dynamic linking) that is at the same privilege level as my code?

Also, why can't I call out to some code segment whose privilege level is the same as mine but belongs to another process?

I guess my question here is the same as the one above: why can't I reach into the GDT and grab segments if I'm executing at cpl 3?

I haven't read in Intel's manual yet that there is hardware support for this restriction.

Is it done at the OS level?

If so, then a more permissive OS should allow me to reach into the GDT and grab segments, right?

Your only 2 code/execute descriptors valid for CS are going to be identical except one is DPL0 (selected by 0x0008) and one is DPL3 (selected by 0x001B) (in 32 bit versions both Windows and Linux I believe).

Why does the OS make two identical code segments for a newly loaded process?

Any as every mainstream OS only typically defines the two execute segment descriptors, any attempt to use anything but those two defined selectors for CS values will result in accessing a invalid or null descriptor and also cause a GPF.

OK, so you're kind of confirming my hunch from above that this restriction on grabbing code segments from the GDT is software enforced by the OS and not hardware enforced, assuming of course that the privilege levels work out.

But again, what about calling out to pre-existing executable framework code that is at the same privilege level as the running process?

Why is this not allowed?

Must a gate be used here?

The segmentation feature of descriptors has basically long been disabled and ignored by having base 0 limit max on all descriptors. In addition there is universal R/W/X enabled in descriptors for the entire memory limit and finer granularity over RWX is now deferred to the page tables post DEP/AMD64 improvements.

There is effectively one global RWX segment and the only thing really left that the selector controls at that point is setting CPL 0 or 3 when switching between kernel mode and user mode, so it's easy to see that the idea of far calls from a application or normal programmer perspective in pmode/lmode essentially don't exist.

How do you keep segments from just running into each other and everything getting mashed together?

There is however an OS called Multics that exists...

The forerunner of UNIX?
 

exdeath

Lifer
Jan 29, 2004
13,679
10
81
It's not an x86 restriction.

Popular mainstream OSes simply do not implement more than one user code segment for ring 3. Segmentation is abandoned for paging, it's only present on x86 legacy as mandatory even to set up a bare minimum to flat mode There are no other selectors to load in Windows, Linux, etc. Any other CS selector load other than 0x001b in an application in 32 bit Windows for example will result in a general protection fault. The only other selectors are

0x0008 kernel execute segment
0x0010 kernel read/write segment
0x001b user execute segment
0x0023 user read/write segment
0x???? Some other stuff used for threading, just aliased data read/write segments that treat some address in the middle of your map as starting at 0 such that pTIB = FS:[0] = pTIB->dsrelativelinearaddress (don't worry about it yet lol)

If you are 0x001b there is nothing else you can load CS with that won't GPF. And obviously you can't write your own either because you can't lgdt in ring 3 and the current GDT physical location is unknown and made inaccessible to you.

If you look at crashes you'll see CS=001B DS=ES=SS=0023 always no matter the application. These both reference the same flat 4GB linear map (overlapping segments) just CS for execute and the rest for R/W that's the only difference. 0x00400000 is the same location relative to CS or DS/ES/SS. When you use a MOV it's using DS and has R/W. When you JMP to it you're using CS for execute. You ignore the segment registers basically and just look at 0-4GB as R/W/X, x86 just can't do X and W in the same descriptor so you need 2 per privilege level 0 and 3.

Like I've said before, descriptors are all identical for addressing (0-4GB) and all overlap, they are only used for permission. You have 2 privilege levels kernel and user and you have mutually exclusive code or data bits for both, that's where 4 descriptors comes from. This is the bare minimum you need for x86-32 even if you are using a flat model and setting up paging. This effectively turns off segmentation.

.code/.text/.data are assembler parsing and organization directives and have nothing to do with x86 segmentation. You can put as many .code sections in your .asm as you want, it's all just going to be different linear address offests in the same memory map using the same CS=001B.

When you load DLLs , pages are simpy allocated to your processes private memory map somewhere where there is a free hole and the DLL is loaded there. There are no separate segments. You can read/write those pages with DS=0023 or JMP to it with CS=001B just like any other portion of your program. If they rely on kernel support they will trap with int 2e or sysenter using KiSystemCall via ntdll.dll wrappers that take care of ordinal numbers to call numerous Windows APIs.

Segmentation just isn't used anymore other than the minimum 4 "segments" mandated by x86 to have kernel/user r/w/x with a flat unified memory model, then go to paging. It exists only because the 286 tried to expand the segment model while integrating it with privilege constructs, and the 386 extended it for compatibly/convention then added paging.

Strictly speaking x86 you can do what you want; multiple segments of multiple sizes in differing or overlapping physical memory locations with same or differing privilege level and far jump to other segments of equal CPL=DPL and use all 8191 global descriptor entries if you want. But you'd have to write that yourself completely from scratch. You won't get to play with segments and descriptors in any current mainstream conventional operating system that "disables" segmentation for memory management in favor of paging exclusively.
 
Last edited:

exdeath

Lifer
Jan 29, 2004
13,679
10
81
Saw this today on wiki, good recap on why you need a minimum of 2 segments per privilege level and why a typical OS with 2 privilege levels needs 4 identical segments to disable segmentation.

In protected mode a segment can not be both writable and executable.[2][3] Therefore, when implementing the Tiny memory model the code segment register must point to the same physical address and have the same limit as the data segment register. This defeated one of the features of the 80286, which makes sure data segments are never executable and code segments are never writable (which means that self-modifying code is never allowed). However, on the 80386, with its paged memory management unit it is possible to protect individual memory pages against writing.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
It's not an x86 restriction.

Popular mainstream OSes simply do not implement more than one user code segment for ring 3. Segmentation is abandoned for paging, it's only present on x86 legacy as mandatory even to set up a bare minimum to flat mode There are no other selectors to load in Windows, Linux, etc. Any other CS selector load other than 0x001b in an application in 32 bit Windows for example will result in a general protection fault. The only other selectors are

0x0008 kernel execute segment
0x0010 kernel read/write segment
0x001b user execute segment
0x0023 user read/write segment
0x???? Some other stuff used for threading, just aliased data read/write segments that treat some address in the middle of your map as starting at 0 such that pTIB = FS:[0] = pTIB->dsrelativelinearaddress (don't worry about it yet lol)

If you are 0x001b there is nothing else you can load CS with that won't GPF. And obviously you can't write your own either because you can't lgdt in ring 3 and the current GDT physical location is unknown and made inaccessible to you.

If you look at crashes you'll see CS=001B DS=ES=SS=0023 always no matter the application. These both reference the same flat 4GB linear map (overlapping segments) just CS for execute and the rest for R/W that's the only difference. 0x00400000 is the same location relative to CS or DS/ES/SS. When you use a MOV it's using DS and has R/W. When you JMP to it you're using CS for execute. You ignore the segment registers basically and just look at 0-4GB as R/W/X, x86 just can't do X and W in the same descriptor so you need 2 per privilege level 0 and 3.

Like I've said before, descriptors are all identical for addressing (0-4GB) and all overlap, they are only used for permission. You have 2 privilege levels kernel and user and you have mutually exclusive code or data bits for both, that's where 4 descriptors comes from. This is the bare minimum you need for x86-32 even if you are using a flat model and setting up paging. This effectively turns off segmentation.

.code/.text/.data are assembler parsing and organization directives and have nothing to do with x86 segmentation. You can put as many .code sections in your .asm as you want, it's all just going to be different linear address offests in the same memory map using the same CS=001B.

When you load DLLs , pages are simpy allocated to your processes private memory map somewhere where there is a free hole and the DLL is loaded there. There are no separate segments. You can read/write those pages with DS=0023 or JMP to it with CS=001B just like any other portion of your program. If they rely on kernel support they will trap with int 2e or sysenter using KiSystemCall via ntdll.dll wrappers that take care of ordinal numbers to call numerous Windows APIs.

Segmentation just isn't used anymore other than the minimum 4 "segments" mandated by x86 to have kernel/user r/w/x with a flat unified memory model, then go to paging. It exists only because the 286 tried to expand the segment model while integrating it with privilege constructs, and the 386 extended it for compatibly/convention then added paging.

Strictly speaking x86 you can do what you want; multiple segments of multiple sizes in differing or overlapping physical memory locations with same or differing privilege level and far jump to other segments of equal CPL=DPL and use all 8191 global descriptor entries if you want. But you'd have to write that yourself completely from scratch. You won't get to play with segments and descriptors in any current mainstream conventional operating system that "disables" segmentation for memory management in favor of paging exclusively.

I'm still at the hardware level and not ready to study operating systems yet.

But, all of this seems terribly insecure to me.

What's to stop a user process from executing the code of another user process or the kernel for that matter?

All the code is in segments that all have the same base, namely 0, and maximum limit.

What if you have two programs: program 1 has a code segment in its file that is 1,000 bytes long, and program 2 has a code segment in its file that is 2,000 bytes long.

When the OS loads these two programs and runs both simultaneously, it has to assign some range of the processor's linear address space to process 1 and process 2.

Both processes are executing code from the same user space code segment.

So how does the OS keep track of which chunk of offsets belongs to process 1 and which chunk of offsets belongs to process 2?

Is there some kind of process data element that holds info about running processes in kernel memory?

If so, would the kernel always check offsets to make sure that a process doesn't reach outside of its assigned linear range?

Also, I've heard that modern OSes don't employ hardware level task switching either.

Is this true?

Generally, why would OS designers intentionally not use all of the hardware level protection afforded them?
 
Last edited:

exdeath

Lifer
Jan 29, 2004
13,679
10
81
Given that the portion of hardware we are taking about is the operating system's responsibility to program, and was put into the processor to facilitate OS protection, process isolation, and multitasking, you have to understand both at the same time.

The answer is paging.

Segmentation is no longer used for memory protection, say it with me now! It only controls privilege level for access to privileged instructions and registers. This is why x86 is confusing. It supports both memory models and for legacy reasons, even if you aren't using segmentation and are only using paging, you still have to set up protected mode, eg segments, to use paging! You merely disable the memory translation contribution by setting base 0 limit max for your 4 minimal selectors (discussed previously) so that you only have paging translation. You still have to have a GDT and segment registers and be concious of privilege level but segmentations contribution to the memory translation process is nullified by setting those base and limit values for all segments.

If you just set up the GDT as I've been describing and didn't enable and manage paging to restrict memory and isolate processes, you're absolutely right, you'd have no protection or isolation or ability to multitask cleanly. And this is exactly what single tasking 32 bit DOS games and DOS4GW type extenders did back in the day (more importantly they handled the complex task of facilitating back and forth transitions to real mode to handle DOS and BIOS interrupts designed for real mode addressing only).

Obnoxious construct that they started trying to get rid of partially in AMD64 going forward but you'd instantly break 3 decades of backwards compatibility and every current x86 OS since 1985 (386) changing or removing it completely.

For paging, CR3 is swapped out per process.

The pages above 2GB (or 1GB) are marked supervisor and are inaccessible from user, that includes read/write/exec. This section in the PTD is identical for all user process page tsble directories and has duplicate pointers to the OS page tables so that the operating system is always in the same place and always accessible immediately on an interrupt regardless what process or task is running. This is why there is always a 2/2 GB or 1/3 GB split and the concept of a OS map and user map (64 bit is the same but the memory map size is basically "infinity" ).

This split was more of an impact in needing 64 bit more than a 4GB absolute limit. We ran out of usable address space well before applications needed 4GB actual usable RAM. Intel PAE gave you more physical RAM but you could still only use 2GB or 3GB per process. The OS was getting squeezed as well trying to manage 100s of processes, manage multi GB storage caches, and the big one, mapping linear memory from video cards starting to exceed 1GB+ RAM all by themselves, all in a tiny 2GB map.

Back to paging protection and process isolation.

When CR3 changes by the OS, the portion below the user/supervisor cut instantaneously changes (after TLB flush which iirc is automatic on CR3 load?) to the new processes application memory map (OS doesn't move because the upper part of the PTD is the same, which is a good thing or you'd change the contents of at CS:EIP immediately mid execution after writing to CR3). A call from ring 0 to ring 3 is performed, if I recall, using TSS to facilitate automatic reloading of saved processor state, flags, registers, and stack swap to resume the program where it was last interrupted. Maybe not, TSS is the hardware task switching you are referring to. It still has to be used minimally to save processor state and swap stacks and set up IO permission bitmaps. The TSS structure is still used to hold the state data but the actual built in task switch mechanism is excessively comprehensive thus slow (eg it saves/reloads too much crap) so its avoided? Recalling this from memory.

Immediately on the ring 3 call resuming the previously saved user CS:EIP in the bottom half of the map (hey here is your far call/CS selector load!) the supervisor portion of the memory map vanishes with no read, write, or execute and you will fault due to CPL=3 now after the far call. No touchy.

As your application 1) cannot modify CR3 or the GDT itself because it's ring 3 trying to execute privileged ring 0 instructions and 2) cannot access the OS memory to seek out other page table directories, processes, OS structures, or GDT, you can't even find or modify your OWN page table because it's all in supervisor pages that are ?????????????? in a debugger and if you attempt ANY access the OS takes over due to page fault and 3) you are stuck in your private virtual memory map sandbox unable to see anything that isn't put into your user page tables (or copied to an allocated page you already have by the OS following a syscall request), completely unaware that any other processes or memory exists unless the OS facilitates API calls called by syscall interrupts to provide you that capability. Otherwise you are completely helpless and at the mercy of the OS to do anything. Basically from the applications perspective it's the only thing running, and must go though the OS to interface with the system, which is exactly what we want.
 
Last edited:

exdeath

Lifer
Jan 29, 2004
13,679
10
81
Extra credit:

When you get into virtualization extensions for hardware virtualization to run hypervisors like ESXi, you basically have a privilege level -1 below 0 that lets you both multi task ring 0 processes and more importantly isolate them from knowing about each other.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Given that the portion of hardware we are taking about is the operating system's responsibility to program, and was put into the processor to facilitate OS protection, process isolation, and multitasking, you have to understand both at the same time.

The answer is paging.

Segmentation is no longer used for memory protection, say it with me now! It only controls privilege level for access to privileged instructions and registers. This is why x86 is confusing. It supports both memory models and for legacy reasons, even if you aren't using segmentation and are only using paging, you still have to set up protected mode, eg segments, to use paging! You merely disable the memory translation contribution by setting base 0 limit max for your 4 minimal selectors (discussed previously) so that you only have paging translation. You still have to have a GDT and segment registers and be concious of privilege level but segmentations contribution to the memory translation process is nullified by setting those base and limit values for all segments.

If you just set up the GDT as I've been describing and didn't enable and manage paging to restrict memory and isolate processes, you're absolutely right, you'd have no protection or isolation or ability to multitask cleanly. And this is exactly what single tasking 32 bit DOS games and DOS4GW type extenders did back in the day (more importantly they handled the complex task of facilitating back and forth transitions to real mode to handle DOS and BIOS interrupts designed for real mode addressing only).

Obnoxious construct that they started trying to get rid of partially in AMD64 going forward but you'd instantly break 3 decades of backwards compatibility and every current x86 OS since 1985 (386) changing or removing it completely.

For paging, CR3 is swapped out per process.

The pages above 2GB (or 1GB) are marked supervisor and are inaccessible from user, that includes read/write/exec. This section in the PTD is identical for all user process page tsble directories and has duplicate pointers to the OS page tables so that the operating system is always in the same place and always accessible immediately on an interrupt regardless what process or task is running. This is why there is always a 2/2 GB or 1/3 GB split and the concept of a OS map and user map (64 bit is the same but the memory map size is basically "infinity" ).

This split was more of an impact in needing 64 bit more than a 4GB absolute limit. We ran out of usable address space well before applications needed 4GB actual usable RAM. Intel PAE gave you more physical RAM but you could still only use 2GB or 3GB per process. The OS was getting squeezed as well trying to manage 100s of processes, manage multi GB storage caches, and the big one, mapping linear memory from video cards starting to exceed 1GB+ RAM all by themselves, all in a tiny 2GB map.

Back to paging protection and process isolation.

When CR3 changes by the OS, the portion below the user/supervisor cut instantaneously changes (after TLB flush which iirc is automatic on CR3 load?) to the new processes application memory map (OS doesn't move because the upper part of the PTD is the same, which is a good thing or you'd change the contents of at CS:EIP immediately mid execution after writing to CR3). A call from ring 0 to ring 3 is performed, if I recall, using TSS to facilitate automatic reloading of saved processor state, flags, registers, and stack swap to resume the program where it was last interrupted. Maybe not, TSS is the hardware task switching you are referring to. It still has to be used minimally to save processor state and swap stacks and set up IO permission bitmaps. The TSS structure is still used to hold the state data but the actual built in task switch mechanism is excessively comprehensive thus slow (eg it saves/reloads too much crap) so its avoided? Recalling this from memory.

Immediately on the ring 3 call resuming the previously saved user CS:EIP in the bottom half of the map (hey here is your far call/CS selector load!) the supervisor portion of the memory map vanishes with no read, write, or execute and you will fault due to CPL=3 now after the far call. No touchy.

As your application 1) cannot modify CR3 or the GDT itself because it's ring 3 trying to execute privileged ring 0 instructions and 2) cannot access the OS memory to seek out other page table directories, processes, OS structures, or GDT, you can't even find or modify your OWN page table because it's all in supervisor pages that are ?????????????? in a debugger and if you attempt ANY access the OS takes over due to page fault and 3) you are stuck in your private virtual memory map sandbox unable to see anything that isn't put into your user page tables (or copied to an allocated page you already have by the OS following a syscall request), completely unaware that any other processes or memory exists unless the OS facilitates API calls called by syscall interrupts to provide you that capability. Otherwise you are completely helpless and at the mercy of the OS to do anything. Basically from the applications perspective it's the only thing running, and must go though the OS to interface with the system, which is exactly what we want.

Wait a minute, what about compatibility mode?

In IA-32e mode, there are two sub-modes: compatibility mode where 32-bit code runs in ambient 64-bit space, and full blown 64-bit mode.

To distinguish between the two, there is a bit, the L-bit, in a segment descriptor that tells you what sub-mode the segment should be executed in.

But, if the OS just uses one code segment descriptor for all privilege 3 code, then how do two processes, one in 64-bit and one in compatibility, run side by side?

Does the OS just toggle the L-bit back and forth accordingly?
 
Last edited:

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
I haven't looked at 64 bit implementations of Windows in depth.

I think that maybe the OS just toggles the L-bit in the descriptor.

In Intel's manual, it mentions that when in full 64-bit mode, a sub-mode of IA-32e mode, the CS, SS, DS, and ES segment registers hold segment selectors that point to segment descriptors whose bases are forced, presumably in some kind of internal logic, to 0 despite that their base fields are not necessarily 0 and that limit checks on those segments aren't performed.

So, I would imagine that to switch between 64-bit and legacy sub-modes in IA-32e mode you would just have the kernel toggle the L-bit in the descriptor and switch the descriptor's base from 0 in internal logic to what the descriptor's base actually is in the data structure in the GDT and then perform limit checks.

That's my theory anyway.
 
Last edited:
sale-70-410-exam    | Exam-200-125-pdf    | we-sale-70-410-exam    | hot-sale-70-410-exam    | Latest-exam-700-603-Dumps    | Dumps-98-363-exams-date    | Certs-200-125-date    | Dumps-300-075-exams-date    | hot-sale-book-C8010-726-book    | Hot-Sale-200-310-Exam    | Exam-Description-200-310-dumps?    | hot-sale-book-200-125-book    | Latest-Updated-300-209-Exam    | Dumps-210-260-exams-date    | Download-200-125-Exam-PDF    | Exam-Description-300-101-dumps    | Certs-300-101-date    | Hot-Sale-300-075-Exam    | Latest-exam-200-125-Dumps    | Exam-Description-200-125-dumps    | Latest-Updated-300-075-Exam    | hot-sale-book-210-260-book    | Dumps-200-901-exams-date    | Certs-200-901-date    | Latest-exam-1Z0-062-Dumps    | Hot-Sale-1Z0-062-Exam    | Certs-CSSLP-date    | 100%-Pass-70-383-Exams    | Latest-JN0-360-real-exam-questions    | 100%-Pass-4A0-100-Real-Exam-Questions    | Dumps-300-135-exams-date    | Passed-200-105-Tech-Exams    | Latest-Updated-200-310-Exam    | Download-300-070-Exam-PDF    | Hot-Sale-JN0-360-Exam    | 100%-Pass-JN0-360-Exams    | 100%-Pass-JN0-360-Real-Exam-Questions    | Dumps-JN0-360-exams-date    | Exam-Description-1Z0-876-dumps    | Latest-exam-1Z0-876-Dumps    | Dumps-HPE0-Y53-exams-date    | 2017-Latest-HPE0-Y53-Exam    | 100%-Pass-HPE0-Y53-Real-Exam-Questions    | Pass-4A0-100-Exam    | Latest-4A0-100-Questions    | Dumps-98-365-exams-date    | 2017-Latest-98-365-Exam    | 100%-Pass-VCS-254-Exams    | 2017-Latest-VCS-273-Exam    | Dumps-200-355-exams-date    | 2017-Latest-300-320-Exam    | Pass-300-101-Exam    | 100%-Pass-300-115-Exams    |
http://www.portvapes.co.uk/    | http://www.portvapes.co.uk/    |