'x86 code - Call through ds segment selector?

I am debugging something at the level of 32-bit x86 code on windows using windbg. Something has confused me and and I have whittled it down to a call that appears to go through the ds segment selector, which apparently I don't understand.

This below is just the minimal example to reproduce my confusion, it is not the actual issue I am dealing with.

I have a function in a DLL

__declspec(dllexport) void __cdecl MyDllTest_Cdecl(int i);

void __cdecl MyDllTest_Cdecl(int i)
{
    printf("In MyDll MyDllTest_Cdecl(%d)\n", i);
}

In an executable, I link to the DLL statically and call the function

void __cdecl MyDllTest_Cdecl(int i);

MyDllTest_Cdecl(1);

Debugging the process in windbg, execution is at the site of the function call where I find the following machine code as shown by windbg

call    dword ptr [UseDll_Static!_imp__MyDllTest_Cdecl (00062118)] ds:002b:00062118={MyDll!MyDllTest_Cdecl (68391100)}

I have source mode in windbg off, (l-t) so the trace command (t) should always just single-step through the machine code and not hide anything.

When I use the trace (t) command, execution suddenly moves to 0x68391100 (as the disassembly of the call command showed).

How does this work? Where does the address 0x68391100 come from? An x86 disassembler shows that the machine code ff1518219e00 is

call   DWORD PTR ds:0x00062118

just as windbg shows.

I understand that the compiler/linker/loader uses indirection through call and jmp instructions, especially for calls to a function in a DLL. I see that in other cases but I am able to single-step through each call and jmp that comprise the C-level function call. In this case, it is a single step. So this is not an indirection of call and jmp instructions created by the compiler/linker/loader.

At address 0x00062118 I see the following:

0:000> u 00062118
UseDll_Static!_imp__MyDllTest_Cdecl:
00062118 0011            add     byte ptr [ecx],dl
0006211a 396820          cmp     dword ptr [eax+20h],ebp
0006211d 1139            adc     dword ptr [ecx],edi

So there is no jmp or call there that might be part of an indirection. It is the address of the symbol UseDll_Static!_imp__MyDllTest_Cdecl but the code there looks like garbage.

The symbols can be ignored, I would just like to know how

call   DWORD PTR ds:00062118

moves execution to 0x68391100. The ds register is 0x002b.

I think I basically understand x86 segmentation in real mode. But I thought on modern Windows in protected mode the virtual memory was basically a flat 2^32 address space. Anyway if there was some segmentation offset, in this case it would be 0x68391100 - 0x00062118 which is 0x6832efe8. I would expect offsets to end in one or more zeros.

This may be completely irrelevant but when I try display the 0x002b selector (which is what is in the ds register) with the dg command in windbg it shows

0:000> dg 0x002b
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
002B 00000000 ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

Thanks for any help...it is a simple question but I am trying to avoid focusing on how functions in DLLs are linked and loaded, or focusing on the history of x86 real mode segmentation. I just want to understand at the level of the machine code.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source