Under x64 mode, the return address is not stored in rbp; then, how to trace the call stack?
Another related question:
Since the first four arguments are passed via rcx, rdx, r8, and r9, how should I retrieve them through the stack trace?
Under x64 mode, the return address is not stored in rbp; then, how to trace the call stack?
Another related question:
Since the first four arguments are passed via rcx, rdx, r8, and r9, how should I retrieve them through the stack trace?
> Under x64 mode, the return address is not stored in rbp; then, how to
trace the call stack?
It isn’t stored in EBP in Win32. You are thinking of the frame pointer.
That said, you need to know the number of parameters passed. The x64 uses
RCX, RDX, R8 and R9 to pass the first four parameters. The remaining
parametrs are on tbe stack. There are no pushes of parameters, and no
stack clearing by either the caller or callee. This avoids all kinds of
nasty pipe-breaking insrtuctions. Instead, space is allocated at the top
of the stack, enough to hold the maximum number of parameters, and values
are placed there via mov instructions. There is space allocated for the
first four parameters as well. The called function may, under a variety
of conditions, choose to dave the first four parameters on the stack.
It is extremely challenging to look at an RSP-based memory dump and make
any sense of it. I should add that with /LTCG, I’ve seen parameters
passed in RAX, RBX, etc. The information in the .pdb file tells windbg
how to do a backtrace. I am somewhat of an expert at x86 assembly code,
and I can tell you that even WITH the .cod listings, I would be severely
challenged to decrypt an x64 stack.
joe
Another related question:
Since the first four arguments are passed via rcx, rdx, r8, and r9, how
should I retrieve them through the stack trace?
WINDBG is sponsored by OSR
OSR is hiring!! Info at http://www.osr.com/careers
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminarsTo unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
I would suggest that to get some idea of what is going on, you create a
few .cod listings and work through what they do. Compile them in debug
mode. Then compile them in release mode, and compare the outputs. When
you have completed this exercise, you will understand my previous post at
a much deeper level.
joe
Under x64 mode, the return address is not stored in rbp; then, how to
trace the call stack?Another related question:
Since the first four arguments are passed via rcx, rdx, r8, and r9, how
should I retrieve them through the stack trace?
WINDBG is sponsored by OSR
OSR is hiring!! Info at http://www.osr.com/careers
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminarsTo unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
xxxxx@gmail.com wrote:
Under x64 mode, the return address is not stored in rbp; then, how to trace the call stack?
Another related question:
Since the first four arguments are passed via rcx, rdx, r8, and r9, how should I retrieve them through the stack trace?
Even though they aren’t pushed as part of the call, every stack frame
leaves room to hold rcx, rdx, r8, and r9. The compiler will flush those
registers to the save area if it needs to reuse the registers, or if it
has to call another function. Thus, in many cases, the parameters ARE
located in the stack.
–
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.
> xxxxx@gmail.com wrote:
> Under x64 mode, the return address is not stored in rbp; then, how to
> trace the call stack?
>
> Another related question:
>
> Since the first four arguments are passed via rcx, rdx, r8, and r9, how
> should I retrieve them through the stack trace?Even though they aren’t pushed as part of the call, every stack frame
leaves room to hold rcx, rdx, r8, and r9. The compiler will flush those
registers to the save area if it needs to reuse the registers, or if it
has to call another function. Thus, in many cases, the parameters ARE
located in the stack.
In addition, they will be flushed to the stack when <varargs.h> is used
to access the parameters of a “…” list. Note tat it also does this with
mov instructions and not pushes to maximize pipe flow.
I have a 30-minute lecture on calling conventions. I talk about cdecl,
stdcall, fastcall and even thiscall (the iternal linkage used by
non-static methods). Then I quote Douglas Adams: “There is a theory that
if anyone ever fully understands the Universe, it will immediately
destroyed and replaced with something vastly more complicated. There is
another theory that this has already happened”. Then I explain FPO, and
then talk about Win64 calling conventions, which are weirder than anything
we’ve discussed so far.
joe
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> WINDBG is sponsored by OSR
>
> OSR is hiring!! Info at http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
></varargs.h>
> xxxxx@gmail.com wrote:
> Under x64 mode, the return address is not stored in rbp; then, how to
> trace the call stack?
>
> Another related question:
>
> Since the first four arguments are passed via rcx, rdx, r8, and r9, how
> should I retrieve them through the stack trace?Even though they aren’t pushed as part of the call, every stack frame
leaves room to hold rcx, rdx, r8, and r9. The compiler will flush those
registers to the save area if it needs to reuse the registers, or if it
has to call another function. Thus, in many cases, the parameters ARE
located in the stack.
In addition, they will be flushed to the stack when <varargs.h> is used
to access the parameters of a “…” list. Note tat it also does this with
mov instructions and not pushes to maximize pipe flow.
I have a 30-minute lecture on calling conventions. I talk about cdecl,
stdcall, fastcall and even thiscall (the internal linkage used by
non-static methods). Then I quote Douglas Adams: “There is a theory that
if anyone ever fully understands the Universe, it will immediately
destroyed and replaced with something vastly more complicated. There is
another theory that this has already happened”. Then I explain FPO, and
then talk about Win64 calling conventions, which are weirder than anything
we’ve discussed so far. I show examples of what happens with LTCG, and
the fact that in Win32 the compiler/optimizer is free to invent arbitrary
calling conventions; I even found one place where the caller sets up a
number of registers and transfers control into the middle of the called
function.
joe
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.
>
>
> —
> WINDBG is sponsored by OSR
>
> OSR is hiring!! Info at http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
></varargs.h>
!cmkd.stack makes x64 debugging somewhat easier:
http://www.codemachine.com/tool_cmkd.html
According to the author, it leverages the very principles that where described above so you don’t have to do it by hand. It is good to learn those concepts though because they will come in handy in all sorts of situations while debugging.
As Tim intimated, some functions will push the parameter to the stack anyway. Just disassemble the first few instructions of the function and you will be able to tell whether rcx, rdx et al are pushed.
For those that don’t. the ub command on the return address is very useful to find out where rcx,rdx r8 and r9 came from. Often the parameters can be found on the parent stack frame or are taken from a volatile register which is then pushed on the current stack frame. Sometimes you have have to go up or down a couple of frames but you can usually (though not always) find them somewhere and it makes 64 bit analysis far more interesting than x86.
if this is your own driver you can force them to be pushed to the stack using the /HOMEPARAMS compiler option by adding the following to your sources file
AMD64_FLAGS = $(AMD64_FLAGS) /homeparams
Obviously there will a minor performance hit here so its’ a judgement call whether go use it or not. if you search the archives you will find valid arguments for both sides.