I do not understand the usefulness of the "far call" instruction in a 86 CPU.

On a 32 bits CPU for example each process has an addressing space of 4Gb (0x00000000 to 0xFFFFFFFF).

There can be several executable memory regions in this 4Gb address space.

A "basic CALL" instruction can call any address in this space. for example:

CALL 0x12345678

In this case, EIP register will be pushed on the stack and 0x12345678 value will be assigned to EIP.

To me, a "Far call" is exactly the same thing but it also changes the CS (Code Segment) register. What is the goal of changing this register value ?

Why changing CS register value ?


1 Answer 1


to perform inter segement branching (jump/call) cs needs to be changed

from windbg you can observe kernel code is running in code segment 0x10 while user mode code is running in 0x33 (64 bits) or 0x23 (32 bits)

:\>livekd -b  -c rcs;q | findstr "cs="

:\>cdb -c "r cs;q" cdb.exe | findstr "cs="

:\>cd "c:\Program Files (x86)\Windows Kits\10\Debuggers\x86"

:\>.\cdb -c "r cs;q" .\cdb.exe | findstr "cs="
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246

a 32 bit binary when running in a 64 bit windows uses WoW (windows on windows ) layer to run 64 bit code to perform syscalls employing inter segement calls with same privileges but different selector

77cf8b40 ff252892d977    jmp     dword ptr [ntdll!Wow64Transition (77d99228)] ds:002b:77d99228=77c67000
0:000> t
eax=0007000e ebx=00000000 ecx=ffffffff edx=77cf8b40 esi=77d95ce0 edi=77c76a78
eip=77c67000 esp=04a7f510 ebp=04a7f788 iopl=0         nv up ei pl zr na pe nc
ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
77c67000 ea0970c6773300  jmp     0033:77C67009  <<<< calling 


the queries you pose in edit are probably worth a few lectures and can't be answered justifiably in Q.A site.

you may need to look for Segment Descriptor , Segment Selector ,
Global Descriptor Table , Local Descriptor Table , Segment Translation
and run through AMD and Intel Manuals a few times to get a grip.

cs , fs, ss, es ,gs ds are segment selectors a 16 bit entity

bit 0,1 denotes Requested Privilege Level or RPL

bit 2 denotes Which Descriptor Table (Table Indicator or TI) to use
( GDT or LDT )

bit 3 to 15 denotes the Index


hex | bin               |    index          |  TI     | RPL         |
10  | 0000000000010000  | 0000000000010=0X2 | 0=GDT   | 00=R0/KERNEL|
23  | 0000000000100011  | 0000000000100=0X4 | 0=GDT   | 11=R3/USER  |
33  | 0000000000110011  | 0000000000110=0X6 | 0=GDT   | 11=R3/USER  |

DUMPING First 8 Global Descriptor Table Entries

0: kd> dpp @gdtr L8
fffff804`43856fb0  00000000`00000000
fffff804`43856fb8  00000000`00000000
fffff804`43856fc0  00209b00`00000000 << 0X2
fffff804`43856fc8  00409300`00000000
fffff804`43856fd0  00cffb00`0000ffff << 0X4
fffff804`43856fd8  00cff300`0000ffff
fffff804`43856fe0  0020fb00`00000000 << 0X6
fffff804`43856fe8  00000000`00000000

using dg command to dissect the raw bytes dumped above

0: kd> dg 0x10
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0010 00000000`00000000 00000000`00000000 Code RE Ac 0 Nb By P  Lo 0000029b
0: kd> dg 0x20
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0020 00000000`00000000 00000000`ffffffff Code RE Ac 3 Bg Pg P  Nl 00000cfb
0: kd> dg 0x30
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0030 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P  Lo 000002fb
0: kd>

so between selector 4 and 6 or cs = 0x23 and cs = 0x33

difference in both cs selector is in 0x33 Long Mode or 64 bit code execution is possible
whereas with cs = 0x23 executing 64 bit instruction is not possible

a practical usage can be observed below in the disassembly of same bytes between cs changes

0:000:x86> ? cs
Evaluate expression: 35 = 00000023
0:000:x86> $$ cs is now in 2 bit mode and disassembly will be as x86 see prompt also
0:000:x86> u . l4
77c67000 ea0970c6773300  jmp     0033:77C67009
77c67007 0000            add     byte ptr [eax],al
77c67009 41              inc     ecx
77c6700a ffa7f8000000    jmp     dword ptr [edi+0F8h]
0:000:x86> $$ lets single step
0:000:x86> t
00000000`77c67009 41ffa7f8000000  jmp     qword ptr [r15+0F8h] ds:00000000`77c64758={wow64cpu!CpupReturnFromSimulatedCode (00000000`77c61782)}
0:000> $$ see the x86 garbage disassembly has now a meaningful x64 instruction
0:000> $$ and prompt is not x86 anymore but x64

0:000> u .-9 l6
00000000`77c67000 ea              ???
00000000`77c67001 0970c6          or      dword ptr [rax-3Ah],esi
00000000`77c67004 7733            ja      wow64cpu!KiFastSystemCall+0x39 (00000000`77c67039)
00000000`77c67006 0000            add     byte ptr [rax],al
00000000`77c67008 0041ff          add     byte ptr [rcx-1],al
00000000`77c6700b a7              cmps    dword ptr [rsi],dword ptr [rdi]
0:000> disassembling x86 code as x64 results ingarbage now
  • Thanks for your answer but i do not understand something: CS is a base address or a prefix ? What means 0x0010 for example ? If i make a "JMP FAR 0x0010:0x2000" what will happen ? a jump to 0x2010 ? And what's the difference if i make a near Jump like this: "JMP 0x2010" ? Thanks
    – Bob5421
    Nov 1, 2022 at 6:46
  • edited in a few details take a look but you may have to read a lot about gdt ldt segment selector etc etc
    – blabb
    Nov 1, 2022 at 19:01
  • Thanks a lot. But I do not understand the role of "index" (bits 3 to 15). It as no link with memory addresses ?
    – Bob5421
    Nov 1, 2022 at 21:06
  • i have already stated that the index denotes which gdt / ldt entry to use gdtr * mygdtr[gdtl ] ; x= mygdtl[index_x] y = mygdtl[index_y] etc etc
    – blabb
    Nov 2, 2022 at 3:02
  • On a x86 32 bits cpu, do you think it is possible to access for example 0x12341234 address by multiple ways using different selector value ? Thanks
    – Bob5421
    Nov 2, 2022 at 8:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.