question about symbols

Hello,

I have the following behaviour which I’d like to understand:

debugging win xp sp2, hit a breakpoint at ntdll!NtCreateProcessEx()
current call stack:

ChildEBP RetAddr Args to Child
0013f038 7c818f16 0013f41c 001f0fff 00000000 ntdll!NtCreateProcessEx
0013fa88 7c80235e 00000000 00159278 00158ac0 kernel32!CreateProcessInternalW+0x1327
0013fac0 4ad031dd 00159278 00158ac0 00000000 kernel32!CreateProcessW+0x2c
0013fc20 4ad02db0 001658b8 001618f8 00000000 cmd!ExecPgm+0x22b

The return address is 7c818f16, which is claimed to belong to CreateProcessInternalW.
That looks fine to me, of course this is how a process is normally created on Windows.

But the part I don’t understand is, the address range for CreateProcessInternalW is
0x191eb to 0x194d5 from the beginning of kernel32.dll, which is loaded at 7c800000 in my case.
So the real VA range of CreateProcessInternalW in the process is 7c8191eb - 7c8194d5.

Indeed, running
kd> u kernel32!CreateProcessInternalW
kernel32!CreateProcessInternalW:
7c8191eb 68080a0000 push 0A08h

gives the start address exactly how it should be.

Nevertheless, the address 7c818f16 is also shown as belonging to CreateProcessInternalW:

u 7c818f16
kernel32!CreateProcessInternalW+0x1327:
7c818f16 8985b8f8ffff mov dword ptr [ebp-748h],eax

So my question is: in general, what is the explanation of such address layout,
and secondly, how does the debugger know that address 7c818f16 also belongs to
CreateProcessInternalW ?

xxxxx@yahoo.com wrote:

I have the following behaviour which I’d like to understand:

debugging win xp sp2, hit a breakpoint at ntdll!NtCreateProcessEx()
current call stack:

The return address is 7c818f16, which is claimed to belong to CreateProcessInternalW.
That looks fine to me, of course this is how a process is normally created on Windows.

But the part I don’t understand is, the address range for CreateProcessInternalW is
0x191eb to 0x194d5 from the beginning of kernel32.dll, which is loaded at 7c800000 in my case.
So the real VA range of CreateProcessInternalW in the process is 7c8191eb - 7c8194d5.

Indeed, running
kd> u kernel32!CreateProcessInternalW
kernel32!CreateProcessInternalW:
7c8191eb 68080a0000 push 0A08h

gives the start address exactly how it should be.

Nevertheless, the address 7c818f16 is also shown as belonging to CreateProcessInternalW:

So my question is: in general, what is the explanation of such address
layout, and secondly, how does the debugger know that address 7c818f16
also belongs to CreateProcessInternalW ?

The linker and the system loader both do some very aggressive
optimizations at the binary level that involve reordering of code. The
linker looks for section of common code that can be reused, and combines
them. It also looks for short functions, and replicates them inline (to
reduce jumps and calls). The system loader tries to increase locality
of reference by rearranging chunks of code so that, if A calls B a lot,
their code will be located in the same page, thereby improving the cache
usage.

As a result of all of this, the code for a single function can be spread
all over the place, often intermixed with snippets of other functions.
The linker and the loader both have symbol tables, and the loader tries
to add notations to let windbg figure out what belongs where, but it’s
not always foolproof.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I see, thanks for this info.
Also, where are those symbol tables located?