Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

Alexander Graham Bell is alive and well in New York, and still waiting for a dial tone.


devel / comp.lang.c++ / Re: Custom stack for function invocation (any signature)

SubjectAuthor
* Custom stack for function invocation (any signature)Frederick Virchanza Gotham
`* Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham
 `* Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham
  `* Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham
   `* Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham
    `* Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham
     `* Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham
      `- Re: Custom stack for function invocation (any signature)Frederick Virchanza Gotham

1
Custom stack for function invocation (any signature)

<05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=833&group=comp.lang.c%2B%2B#833

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:ad4:4e8d:0:b0:635:dabe:94 with SMTP id dy13-20020ad44e8d000000b00635dabe0094mr4714qvb.11.1689259089519;
Thu, 13 Jul 2023 07:38:09 -0700 (PDT)
X-Received: by 2002:a05:6808:1691:b0:3a3:d677:6c78 with SMTP id
bb17-20020a056808169100b003a3d6776c78mr2262290oib.2.1689259089062; Thu, 13
Jul 2023 07:38:09 -0700 (PDT)
Path: i2pn2.org!i2pn.org!usenet.blueworldhosting.com!diablo1.usenet.blueworldhosting.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Thu, 13 Jul 2023 07:38:08 -0700 (PDT)
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.182.117; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.182.117
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
Subject: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Thu, 13 Jul 2023 14:38:09 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 12024
 by: Frederick Virchanza - Thu, 13 Jul 2023 14:38 UTC

Three months ago I posted here about using your own custom stack for one invocation of a function:

https://groups.google.com/g/comp.lang.c++/c/m1uMfMv1fjE

In my 2nd post in that thread, I share code that also supports exception handling:

https://godbolt.org/z/M9544Meqq

Up until now though, I've only had this working with very simple functions that have the signature:

void Func(void);

Today I've written it to support functions that have any signature (any number of parameters, and also a return value).

I start off with three thread_local global variables:

thread_local char *p_original, *p_replacement;
thread_local void (*f)(void);

'p_original' will hold the address of the original stack
'p_replacement' will hold the address of the replacement stack
'f' will hold the address of the function to be invoked

Accessing thread_local variables from assembler can be a little difficult (particularly when writing inline assembler inside a C++ source file), and so to make this a little easier, I've written four functions in C++ to get/set the thread_local variables for me:

char *Get_p_original(void) { return p_original; }
void Set_p_original(char *const arg) { p_original = arg; }
char *Get_p_replacement(void) { return p_replacement; }
void (*Get_f(void))(void) { return f; }

The x86_64 assembler for the getter functions will put the address inside the 'RAX' register. For example the assembler for "Get_f" will simply be:

mov rax, fs:f
ret

The 'set' function will expect the sole function argument to be inside the RDI register on Linux (or inside the RCX register on Microsoft Windows).

I'm going to write a function in Assembler called 'set_stack_pointer_and_invoke', the purpose of which is to change the stack pointer, invoke the function, then restore the original stack pointer. Note that the stack must be intact inside this function before I invoke the target function (so if I push anything onto the stack, I must pop it off the stack before invoking the target function). Here's the inline assembler for the GNU compiler:

__asm("Assembler_set_stack_pointer_and_invoke:\n"
".intel_syntax noprefix \n"
// Step 1: Save the original stack pointer
" push rdi \n" // Save 'rdi' to restore it later
" mov rdi, rsp \n"
" add rdi, 8 \n" // Stack pointer value before we pushed 'rdi'
" call Set_p_original \n" // sets p_original to 'rdi'
" pop rdi \n"
// Step 2: Retrieve the replacement stack pointer
" call Get_p_replacement \n" // sets 'rax' to p_replacement
" mov rsp, rax \n"
// Step 3: Retrieve the address of the function
" call Get_f \n" // sets 'rax' to 'f'
// Step 4: Invoke the function
" call rax \n" // --- Invoke the function!
// Step 5: Save the return value
" push rax \n" // keep track of lower 64 bits of the return value
" push rdx \n" // keep track of higher 64 bits of the return value
// Step 6: Retrieve the original stack pointer
" call Get_p_original \n" // sets 'rax' to p_original
" mov rcx, rax \n" // 'rcx' is caller-saved on Linux, so we can clobber it
// Step 7: Restore the return value
" pop rdx \n"
" pop rax \n"
// Step 8: Restore the original stack pointer
" mov rsp, rcx \n"
" ret \n" // return
".att_syntax");

So next what I did was write a class called 'Stacker' which manages the new custom stack:

class Stacker {
char *p;
std::unique_ptr<char[]> mystack;

public:

Stacker(std::size_t const len) noexcept(false) // might throw bad_alloc
{
assert( len >= 128u );

mystack.reset( new char[len] );
p = mystack.get() + len - 16u;
}

Stacker(char *const arg, std::size_t const len) noexcept
{
assert( nullptr != arg );
assert( len >= 128u );

p = arg + len - 16u;
}

template<typename R, typename... Params>
Invoker<R,Params...> operator()( R(*const arg)(Params...) )
{
return Invoker<R,Params...>(this->p, arg);
}
};

So you create a 'Stacker' object with the size of the stack you want, and you use 'operator()' to give it the address of the function you want to invoke, so you use it as follows:

Stacker(1048576000u)(MyTargetFunction)

The 'operator()' returns an object of type 'Invoker', which is defined as follows:

template<typename R, typename... Params>
class Invoker {
public:
Invoker(char *const arg_p, R(*const arg_f)(Params...))
{
p_replacement = arg_p; // sets a thread_local variable
f = reinterpret_cast<void (*)(void)>(arg_f); // sets a thread_local variable
}

R operator()(Params... args) // This could be static function but I like operator()
{
R (*const funcptr)(Params...) = reinterpret_cast<R(*)(Params....)>(Assembler_set_stack_pointer_and_invoke);
return funcptr(args...);
}
};

And so let's say we want to invoke the following function:

int Func2(double a, float b, short c)
{
return a + b + c;
}

So then we would use the Stacker as follows:

int retval = Stacker(1048576000u)(Func2)(2.0, 3.0f, 8);

A simplified version of the code is up on GodBolt:

https://godbolt.org/z/rTvqs4jvY

The only limitation of this technique is that the return value must be <= 16 bytes (because the lower 64 bits go in RAX, and the upper 64 bits go in RDX). Where the return value is > 16 bytes, the return value is pushed onto the stack -- and I haven't coded the solution for that yet (it will be tricky).

And here's the full code copy-pasted:

#include <cassert> // assert
#include <cstddef> // size_t
#include <memory> // unique_ptr

inline static thread_local char *p_original, *p_replacement;
inline static thread_local void (*f)(void);

extern "C" {
void Assembler_set_stack_pointer_and_invoke(void) noexcept;

char *Get_p_original(void) { return p_original; }
void Set_p_original(char *const arg) { p_original = arg; }
char *Get_p_replacement(void) { return p_replacement; }
void (*Get_f(void))(void) { return f; }
}

template<typename R, typename... Params>
class Invoker {
public:
Invoker(char *const arg_p, R(*const arg_f)(Params...))
{
p_replacement = arg_p; // sets a thread_local variable
f = reinterpret_cast<void (*)(void)>(arg_f); // sets a thread_local variable
}

R operator()(Params... args) // This could be static function but I like operator()
{
R (*const funcptr)(Params...) = reinterpret_cast<R(*)(Params...)>(Assembler_set_stack_pointer_and_invoke);
return funcptr(args...);
}
};

class Stacker {
char *p;
std::unique_ptr<char[]> mystack;

public:

Stacker(std::size_t const len) noexcept(false) // might throw bad_alloc
{
assert( len >= 128u );

mystack.reset( new char[len] );
p = mystack.get() + len - 16u;
}

Stacker(char *const arg, std::size_t const len) noexcept
{
assert( nullptr != arg );
assert( len >= 128u );

p = arg + len - 16u;
}

template<typename R, typename... Params>
Invoker<R,Params...> operator()( R(*const arg)(Params...) )
{
return Invoker<R,Params...>(this->p, arg);
}
};

__asm("Assembler_set_stack_pointer_and_invoke:\n"
".intel_syntax noprefix \n"
// Step 1: Save the original stack pointer
" push rdi \n" // Save 'rdi' to restore it later
" mov rdi, rsp \n"
" add rdi, 8 \n" // Stack pointer value before we pushed 'rdi'
" call Set_p_original \n" // sets p_original to 'rdi'
" pop rdi \n"
// Step 2: Retrieve the replacement stack pointer
" call Get_p_replacement \n" // sets 'rax' to p_replacement
" mov rsp, rax \n"
// Step 3: Retrieve the address of the function
" call Get_f \n" // sets 'rax' to 'f'
// Step 4: Invoke the function
" call rax \n" // --- Invoke the function!
// Step 5: Save the return value
" push rax \n" // keep track of lower 64 bits of the return value
" push rdx \n" // keep track of higher 64 bits of the return value
// Step 6: Retrieve the original stack pointer
" call Get_p_original \n" // sets 'rax' to p_original
" mov rcx, rax \n" // 'rcx' is caller-saved on Linux, so we can clobber it
// Step 7: Restore the return value
" pop rdx \n"
" pop rax \n"
// Step 8: Restore the original stack pointer
" mov rsp, rcx \n"
" ret \n" // return
".att_syntax");


Click here to read the complete article
Re: Custom stack for function invocation (any signature)

<4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=835&group=comp.lang.c%2B%2B#835

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:a05:620a:28ca:b0:765:8643:12f3 with SMTP id l10-20020a05620a28ca00b00765864312f3mr5179qkp.8.1689260999367;
Thu, 13 Jul 2023 08:09:59 -0700 (PDT)
X-Received: by 2002:a05:6808:144a:b0:3a3:a8d1:1aa4 with SMTP id
x10-20020a056808144a00b003a3a8d11aa4mr2228923oiv.2.1689260998953; Thu, 13 Jul
2023 08:09:58 -0700 (PDT)
Path: i2pn2.org!i2pn.org!usenet.blueworldhosting.com!diablo1.usenet.blueworldhosting.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Thu, 13 Jul 2023 08:09:58 -0700 (PDT)
In-Reply-To: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.182.117; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.182.117
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Thu, 13 Jul 2023 15:09:59 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 1914
 by: Frederick Virchanza - Thu, 13 Jul 2023 15:09 UTC

Half an hour ago, I posted:
>
>
> // Step 4: Invoke the function
> " call rax \n" // --- Invoke the function!

Ah crap, I realised just now that I'm editing the stack here. The return address is pushed onto the stack when I invoke the 'call' instruction. This hasn't caused a malfunction because none of the function arguments are on the stack. The code would malfunction if the target function were to have more than 6 parameters, as the 7th would be pushed onto the stack.

Somehow I need to have a 'jmp' instruction instead of a 'call' instruction here. . . and yet somehow have control over where it jumps back to. I need to make a change to the caller of the caller.

Re: Custom stack for function invocation (any signature)

<990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=840&group=comp.lang.c%2B%2B#840

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:a05:620a:2548:b0:767:e807:e4fe with SMTP id s8-20020a05620a254800b00767e807e4femr4637qko.4.1689266527879;
Thu, 13 Jul 2023 09:42:07 -0700 (PDT)
X-Received: by 2002:a05:6870:d883:b0:1b3:7919:e9dd with SMTP id
dv3-20020a056870d88300b001b37919e9ddmr2241285oab.5.1689266526161; Thu, 13 Jul
2023 09:42:06 -0700 (PDT)
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Thu, 13 Jul 2023 09:42:05 -0700 (PDT)
In-Reply-To: <4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.182.117; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.182.117
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com> <4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Thu, 13 Jul 2023 16:42:07 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
 by: Frederick Virchanza - Thu, 13 Jul 2023 16:42 UTC

About an hour ago, I wrote:
> Half an hour ago, I posted:
> >
> >
> > // Step 4: Invoke the function
> > " call rax \n" // --- Invoke the function!
> Ah crap, I realised just now that I'm editing the stack here. The return address is pushed onto the stack when I invoke the 'call' instruction. This hasn't caused a malfunction because none of the function arguments are on the stack. The code would malfunction if the target function were to have more than 6 parameters, as the 7th would be pushed onto the stack.
>
> Somehow I need to have a 'jmp' instruction instead of a 'call' instruction here. . .
> and yet somehow have control over where it jumps back to. I need to make a
> change to the caller of the caller.

I have an idea. When the assembler function is entered, the return address is at the top of the stack. So the first thing I will do is copy the return address to a global thread_local variable. Next I will edit the return address at the top of the stack. Then I will change the 'call' to a 'jmp', and then later when it 'ret' back to my own location, I will then jump back to the address that I stored in the thread_local variable.

Furthermore, if the target function returns a very very big struct by value, and therefore pushes a portion of the return value onto the stack, then I can compare the stack pointer before and after the call, something like:

old = get_stack_ptr();
InvokeTargetFunction();
new = get_stack_ptr();
if ( new < old )
{
bytes_to_copy = old - new;
memcpy( original_stack -= bytes_to_copy, custom_stack, bytes_to_copy );
}

I'll try code this when I'm home later.

Re: Custom stack for function invocation (any signature)

<d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=843&group=comp.lang.c%2B%2B#843

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:ad4:4e03:0:b0:635:de3c:17da with SMTP id dl3-20020ad44e03000000b00635de3c17damr6990qvb.6.1689285025718;
Thu, 13 Jul 2023 14:50:25 -0700 (PDT)
X-Received: by 2002:a05:6808:1592:b0:3a3:c493:b971 with SMTP id
t18-20020a056808159200b003a3c493b971mr3971527oiw.7.1689285025413; Thu, 13 Jul
2023 14:50:25 -0700 (PDT)
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Thu, 13 Jul 2023 14:50:24 -0700 (PDT)
In-Reply-To: <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.182.118; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.182.118
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
<4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com> <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Thu, 13 Jul 2023 21:50:25 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
 by: Frederick Virchanza - Thu, 13 Jul 2023 21:50 UTC

On Thursday, July 13, 2023 at 5:42:17 PM UTC+1, Frederick Virchanza Gotham wrote:
>
> Furthermore, if the target function returns a very very big struct by value, and therefore pushes a portion of the return value onto the stack, then I can compare the stack pointer before and after the call, something like:
>
> old = get_stack_ptr();
> InvokeTargetFunction();
> new = get_stack_ptr();
> if ( new < old )
> {
> bytes_to_copy = old - new;
> memcpy( original_stack -= bytes_to_copy, custom_stack, bytes_to_copy );
> }
>
> I'll try code this when I'm home later.

It seems I now have it working when supernumerary arguments which are passed on the stack:

https://godbolt.org/z/azs6o6sv6

The next step will be to get it to work with return values that are greater than 16 bytes (because then the return value will be pushed to the stack). The final step will be to get it working with exception handling (but that's far off in the distance).

And here it is copy-pasted:

#include <cassert> // assert
#include <cstddef> // size_t
#include <memory> // unique_ptr

thread_local char *p_original, *p_replacement;
thread_local void (*f)(void);
thread_local char *bottom_of_stack;

extern "C" {
void Assembler_set_stack_pointer_and_invoke(void) noexcept;

char *Get_p_original(void) { return p_original; }
void Set_p_original(char *const arg) { p_original = arg; }
char *Get_p_replacement(void) { return p_replacement; }
void (*Get_f(void))(void) { return f; }

char *Get_bottom_of_stack(void) { return bottom_of_stack; }
void Set_bottom_of_stack(char *const arg) { bottom_of_stack = arg; }

void Assembler_set_bottom_of_stack(void) noexcept;
}

__asm("Assembler_set_bottom_of_stack: \n"
".intel_syntax noprefix \n"
" push rdi \n"
" mov rdi, rsp \n"
" add rdi, 16 \n"
" call Set_bottom_of_stack \n"
" pop rdi \n"
" ret \n"
".att_syntax");

template<typename R, typename... Params>
class Invoker {
public:
Invoker(char *const arg_p, R(*const arg_f)(Params...))
{
p_replacement = arg_p; // sets a thread_local variable
f = reinterpret_cast<void (*)(void)>(arg_f); // sets a thread_local variable
}

R operator()(Params... args) // This could be static function but I like operator()
{
Assembler_set_bottom_of_stack();
R (*const funcptr)(Params...) = reinterpret_cast<R(*)(Params...)>(Assembler_set_stack_pointer_and_invoke);
return funcptr( std::forward<Params>(args)... );
}
};

class Stacker {
char *p;
std::unique_ptr<char[]> mystack;

public:

Stacker(std::size_t const len) noexcept(false) // might throw bad_alloc
{
assert( len >= 128u );

mystack.reset( new char[len] );
p = mystack.get() + len - 16u;
}

Stacker(char *const arg, std::size_t const len) noexcept
{
assert( nullptr != arg );
assert( len >= 128u );

p = arg + len - 16u;
}

template<typename R, typename... Params>
Invoker<R,Params...> operator()( R(*const arg)(Params...) )
{
return Invoker<R,Params...>(this->p, arg);
}
};

__asm("Assembler_set_stack_pointer_and_invoke:\n"
".intel_syntax noprefix \n"
// Step 1: Save the original stack pointer
" push r15 \n" // save just to restore later
" push r14 \n" // save just to restore later
" push rdi \n" // save just to restore later
" mov rdi, rsp \n"
" add rdi, 24 \n" // Stack pointer value before we pushed anything
" call Set_p_original \n" // sets p_original to 'rdi'
// Step 2: Retrieve the replacement stack pointer
" call Get_p_replacement \n" // sets 'rax' to p_replacement
" mov r15, rax \n"
" call Get_bottom_of_stack \n"
// Right now: RDI is the top of the old stack
// RAX is the bottom of the old stack
// R15 is the top of the new stack
// We want to do:
// while ( rax != rdi ) *r15-- = *rax--;
" jmp cond \n" // Jump to condition first
"loop: \n"
" mov r14, qword ptr [rax] \n"
" mov qword ptr [r15], r14 \n"
" sub r15, 1 \n"
" sub rax, 1 \n"
"cond: \n"
" cmp rax,rdi \n"
" jne loop \n"
" add r15, 8 \n"
" mov rax, r15 \n"
" pop rdi \n"
" pop r14 \n"
" pop r15 \n"
" mov rsp, rax \n" // ====================================== new stack
// Step 3: Retrieve the address of the function
" call Get_f \n" // sets 'rax' to 'f'
// Step 4: Set the return address to after the jump instruction
" lea r15,[Label_Jump_Back] \n"
" push r15 \n"
// Step 5: Invoke the function
" jmp rax \n" // --- Invoke the function!
"Label_Jump_Back:"
// Step 6: Save the return value
" push rax \n" // keep track of lower 64 bits of the return value
// Step 7: Retrieve the original stack pointer
" call Get_p_original \n" // sets 'rax' to p_original
" mov rcx, rax \n" // 'rcx' is caller-saved on Linux, so we can clobber it
// Step 8: Restore the return value
" pop rax \n"
// Step 9: Restore the original stack pointer
" mov rsp, rcx \n"
// Step 10: Jump back to the original address
" ret \n"
".att_syntax");

// =================== And now the test code ==============================================
#include <iostream> // cout, endl
using std::cout, std::endl;

struct VeryBigStruct {
double a[3];
int b[3];
double c[3];
int d[3];
double e[3];
int f[3];
};

int Func2(VeryBigStruct arg)
{ return arg.a[1] + arg.b[2] + arg.f[2];
}

int main(void)
{ cout << "first line in main\n";

VeryBigStruct vbs;
vbs.a[1] = 3;
vbs.b[2] = 4;
vbs.f[2] = 5;

cout << "Retval: " << Func2(vbs) << endl;

cout << "Retval: " << Stacker(1048576000u)(Func2)(vbs) << endl;

cout << "last line in main\n";
}

Re: Custom stack for function invocation (any signature)

<84f722fb-1263-4226-aa3b-d19c7c81b00cn@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=845&group=comp.lang.c%2B%2B#845

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:a05:620a:17a2:b0:767:dcda:b35d with SMTP id ay34-20020a05620a17a200b00767dcdab35dmr9091qkb.7.1689326348968;
Fri, 14 Jul 2023 02:19:08 -0700 (PDT)
X-Received: by 2002:a05:6808:1529:b0:3a4:1265:312d with SMTP id
u41-20020a056808152900b003a41265312dmr6034968oiw.5.1689326348658; Fri, 14 Jul
2023 02:19:08 -0700 (PDT)
Path: i2pn2.org!i2pn.org!usenet.blueworldhosting.com!diablo1.usenet.blueworldhosting.com!peer01.iad!feed-me.highwinds-media.com!news.highwinds-media.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Fri, 14 Jul 2023 02:19:08 -0700 (PDT)
In-Reply-To: <d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=82.153.25.131; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 82.153.25.131
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
<4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com> <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
<d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <84f722fb-1263-4226-aa3b-d19c7c81b00cn@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Fri, 14 Jul 2023 09:19:08 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 2240
 by: Frederick Virchanza - Fri, 14 Jul 2023 09:19 UTC

On Thursday, July 13, 2023 at 10:50:35 PM UTC+1, Frederick Virchanza Gotham wrote:
>
> The next step will be to get it to work with return values that are greater
> than 16 bytes (because then the return value will be pushed to the stack)..

I was wrong about this. If the callee returns a struct bigger than 16 bytes, then it is the caller function that allocates memory on the stack, and then the caller passes the address of this allocated memory in the RDI register to the callee. So the stack pointer will always be the same before and after a function call.

So it looks like my code is already complete -- I have figured out a way to call _any_ function with a custom stack using the System V x86_64 calling convention.

Soon I'll look at allowing it to handle exceptions thrown from the callee.

Re: Custom stack for function invocation (any signature)

<770c748e-6b98-4c08-8d9f-493e1ef0edc4n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=851&group=comp.lang.c%2B%2B#851

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:a05:620a:1a27:b0:765:2eef:e3c3 with SMTP id bk39-20020a05620a1a2700b007652eefe3c3mr11418qkb.3.1689336066104;
Fri, 14 Jul 2023 05:01:06 -0700 (PDT)
X-Received: by 2002:a05:6808:2188:b0:3a0:50ed:d772 with SMTP id
be8-20020a056808218800b003a050edd772mr6185948oib.5.1689336065794; Fri, 14 Jul
2023 05:01:05 -0700 (PDT)
Path: i2pn2.org!i2pn.org!news.swapon.de!news.mixmin.net!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Fri, 14 Jul 2023 05:01:05 -0700 (PDT)
In-Reply-To: <84f722fb-1263-4226-aa3b-d19c7c81b00cn@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=82.153.25.131; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 82.153.25.131
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
<4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com> <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
<d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com> <84f722fb-1263-4226-aa3b-d19c7c81b00cn@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <770c748e-6b98-4c08-8d9f-493e1ef0edc4n@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Fri, 14 Jul 2023 12:01:06 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
 by: Frederick Virchanza - Fri, 14 Jul 2023 12:01 UTC

On Friday, July 14, 2023 at 10:19:19 AM UTC+1, I wrote:
>
> So it looks like my code is already complete -- I have figured out a way to call _any_ function
> with a custom stack using the System V x86_64 calling convention.

I figured out how to access thread_local variables from inside "inline assembler" with the GNU compiler, so I've been able to simply my code further:

https://godbolt.org/z/jY7G7EMYb

And here it is copy-pasted:

#include <cassert> // assert
#include <cstddef> // size_t
#include <memory> // unique_ptr
#include <utility> // forward

thread_local char *p_original, *p_replacement;
thread_local void (*f)(void);
thread_local char *bottom_of_stack;

extern "C" {
void Assembler_set_bottom_of_stack (void) noexcept;
void Assembler_set_stack_pointer_and_invoke(void) noexcept;
}

__asm("Assembler_set_bottom_of_stack: \n"
".intel_syntax noprefix \n"
" mov r10, rsp \n"
" add r10, 16 \n" // +8 return addr, +8 to be safe
" mov QWORD PTR fs:bottom_of_stack@tpoff, r10 \n"
" ret \n"
".att_syntax");

template<typename R, typename... Params>
class Invoker {

Invoker(char *const arg_p, R(*const arg_f)(Params...)) noexcept
{
p_replacement = arg_p; // sets a thread_local variable
f = reinterpret_cast<void (*)(void)>(arg_f); // sets a thread_local variable
}

public:
R operator()(Params... args) // This could be static function but I like operator()
{
Assembler_set_bottom_of_stack();
R (*const funcptr)(Params...) = reinterpret_cast<R(*)(Params...)>(Assembler_set_stack_pointer_and_invoke);
return funcptr( std::forward<Params>(args)... );
}

friend class Stacker;
};

class Stacker {
char *p;
std::unique_ptr<char[]> mystack;

public:

Stacker(std::size_t const len) noexcept(false) // might throw bad_alloc
{
assert( len >= 128u );

mystack.reset( new char[len] );
p = mystack.get() + len - 16u;
}

Stacker(char *const arg, std::size_t const len) noexcept
{
assert( nullptr != arg );
assert( len >= 128u );

p = arg + len - 16u;
}

template<typename R, typename... Params>
Invoker<R,Params...> operator()( R(*const arg)(Params...) )
{
return Invoker<R,Params...>(this->p, arg);
}
};

/* In the following function written in x86_64 assembler using
the System V calling convention, we can only clobber r10
and r11 because all of the other caller-saved registers
must be preserved for the 'jmp' to the target function. */

__asm("Assembler_set_stack_pointer_and_invoke:\n"
".intel_syntax noprefix \n"
// Step 1: Save the original stack pointer
" mov QWORD PTR fs:p_original@tpoff, rsp \n"
// Step 2: Retrieve the replacement stack pointer
" push r15 \n" // save to restore later
" mov r15, rsp \n" // pointer to the r15 we just pushed onto stack
" add r15, 8 \n" // sets 'r15' to top of old stack
" mov r10, QWORD PTR fs:p_replacement@tpoff \n" // sets 'r10' to top of new stack
" mov rax, QWORD PTR fs:bottom_of_stack@tpoff \n" // sets 'rax' to bottom of old stack
// Right now: R15 is the top of the old stack
// R10 is the top of the new stack
// RAX is the bottom of the old stack
// We want to do:
// while ( rax != r15 ) *r10-- = *rax--;
// Step 3: Copy the old stack to the new stack (it might contain supernumerary arguments or a big return struct)
" jmp cond \n" // Jump to condition of 'while' loop
"loop: \n" // ----<----<----<----<----
" mov r11, qword ptr [rax] \n" // |
" mov qword ptr [r10], r11 \n" // ^
" sub r10, 1 \n" // | Loop
" sub rax, 1 \n" // |
"cond: \n" // ^
" cmp rax, r15 \n" // |
" jne loop \n" // ---->---->---->---->----
" pop r15 \n" // restore original value
// Step 4: Change the stack pointer to the new stack ============================================ " mov rsp, r10 \n" // ================================================= new stack
// Step 5: Set the return address to after the 'jmp' instruction
" lea r10, [Label_Jump_Back] \n"
" add rsp, 8 \n" // This line and the next line replace the return address on the stack
" push r10 \n" // This line and the previous line replace the return address on the stack
// Step 5: Invoke the function
" jmp QWORD PTR fs:f@tpoff \n" // --- Invoke the function!
"Label_Jump_Back: \n"
// Note: The label has already been popped off the stack by the callee
// Step 9: Restore the original stack pointer
" mov rsp, QWORD PTR fs:p_original@tpoff \n"
// Step 10: Jump back to the original address
" ret \n"
".att_syntax");

// =================== And now the test code ==============================================
#include <iostream> // cout, endl
using std::cout, std::endl;

struct VeryBigStruct {
double a[3];
int b[3];
double c[3];
int d[3];
double e[3];
int f[3];
};

VeryBigStruct Func2(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10)
{ VeryBigStruct vbs;
vbs.f[2] = a1+a2+a3+a4+a5+a6+a7+a8+a9+a10;
return vbs;
}

int main(void)
{ cout << "first line in main\n";

VeryBigStruct vbs;
vbs.a[1] = 7;
vbs.b[2] = 8;
vbs.f[2] = 9;

cout << "Retval: " << Func2(1,2,3,4,5,6,7,8,9,10).f[2] << endl;

cout << "Retval: " << Stacker(1048576000u)(Func2)(1,2,3,4,5,6,7,8,9,10)..f[2] << endl;

cout << "last line in main\n";
}

Re: Custom stack for function invocation (any signature)

<d19d9ffa-cb8d-425f-99f4-b5a914e67cc8n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=870&group=comp.lang.c%2B%2B#870

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:a05:620a:4688:b0:767:dcd6:61ae with SMTP id bq8-20020a05620a468800b00767dcd661aemr22795qkb.6.1689386159063;
Fri, 14 Jul 2023 18:55:59 -0700 (PDT)
X-Received: by 2002:ac8:5356:0:b0:403:a73b:893b with SMTP id
d22-20020ac85356000000b00403a73b893bmr26841qto.3.1689386158737; Fri, 14 Jul
2023 18:55:58 -0700 (PDT)
Path: i2pn2.org!i2pn.org!usenet.blueworldhosting.com!diablo1.usenet.blueworldhosting.com!peer03.iad!feed-me.highwinds-media.com!news.highwinds-media.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Fri, 14 Jul 2023 18:55:58 -0700 (PDT)
In-Reply-To: <770c748e-6b98-4c08-8d9f-493e1ef0edc4n@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.182.234; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.182.234
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
<4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com> <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
<d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com> <84f722fb-1263-4226-aa3b-d19c7c81b00cn@googlegroups.com>
<770c748e-6b98-4c08-8d9f-493e1ef0edc4n@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <d19d9ffa-cb8d-425f-99f4-b5a914e67cc8n@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Sat, 15 Jul 2023 01:55:59 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 2362
 by: Frederick Virchanza - Sat, 15 Jul 2023 01:55 UTC

On Friday, July 14, 2023 at 1:01:31 PM UTC+1, Frederick Virchanza Gotham wrote:
>
> I figured out how to access thread_local variables from inside "inline assembler"
> with the GNU compiler, so I've been able to simply my code further:

I'm trying to support exception handling now but the following is segfaulting:

https://godbolt.org/z/84xMojEb4

Anyone know what's wrong? The segfault is happening inside "uw_update_context_1" when it tries to make a copy of the '_Unwind_Context' struct. Specifically it's dying on Line #1143 of libgcc/unwind-dw2.c

I was able to get this working a few months ago with functions that take no parameters and have no return value, but I can't get it working with my current code for functions with _any_ signature. Here's the old code:

https://godbolt.org/z/M9544Meqq

Re: Custom stack for function invocation (any signature)

<c74af3de-4998-4960-8c70-f56abc594b85n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=879&group=comp.lang.c%2B%2B#879

  copy link   Newsgroups: comp.lang.c++
X-Received: by 2002:a05:620a:f12:b0:765:a78f:dd24 with SMTP id v18-20020a05620a0f1200b00765a78fdd24mr50356qkl.9.1689428536423;
Sat, 15 Jul 2023 06:42:16 -0700 (PDT)
X-Received: by 2002:a4a:458c:0:b0:566:238a:3c55 with SMTP id
y134-20020a4a458c000000b00566238a3c55mr1485852ooa.1.1689428536106; Sat, 15
Jul 2023 06:42:16 -0700 (PDT)
Path: i2pn2.org!i2pn.org!usenet.goja.nl.eu.org!3.eu.feeder.erje.net!feeder.erje.net!fdn.fr!proxad.net!feeder1-2.proxad.net!209.85.160.216.MISMATCH!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.lang.c++
Date: Sat, 15 Jul 2023 06:42:15 -0700 (PDT)
In-Reply-To: <d19d9ffa-cb8d-425f-99f4-b5a914e67cc8n@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=94.119.64.57; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 94.119.64.57
References: <05d2fc9e-088e-41a6-9039-2de1717ba952n@googlegroups.com>
<4b5f0bd6-0816-4800-b8bd-adfae203932cn@googlegroups.com> <990646ef-4d2c-411b-8c19-e90cd3eacbfcn@googlegroups.com>
<d685c246-5c1b-4640-86c6-b20dd271287dn@googlegroups.com> <84f722fb-1263-4226-aa3b-d19c7c81b00cn@googlegroups.com>
<770c748e-6b98-4c08-8d9f-493e1ef0edc4n@googlegroups.com> <d19d9ffa-cb8d-425f-99f4-b5a914e67cc8n@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <c74af3de-4998-4960-8c70-f56abc594b85n@googlegroups.com>
Subject: Re: Custom stack for function invocation (any signature)
From: cauldwell.thomas@gmail.com (Frederick Virchanza Gotham)
Injection-Date: Sat, 15 Jul 2023 13:42:16 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
 by: Frederick Virchanza - Sat, 15 Jul 2023 13:42 UTC

On Saturday, July 15, 2023 at 2:56:08 AM UTC+1, Frederick Virchanza Gotham wrote:
>
> I'm trying to support exception handling now but the following is segfaulting:

I'm trying to get it working with exception handling, but it's segfaulting. I've tried copying the entire stack but it's still segfaulting inside libgcc inside the function "uw_update_context_1" when it tries to copy the context struct. Anybody know what's wrong with the following?

https://godbolt.org/z/vv7hTGWdr

And here it is copy-pasted:

#include <cassert> // assert
#include <cstddef> // size_t
#include <climits> // ULONG_LONG_MAX
#include <cstdlib> // strtoull
#include <cstring> // strstr
#include <cstdint> // UINTPTR_MAX
#include <memory> // unique_ptr
#include <utility> // forward
#include <exception> // exception_ptr, current_exception
#include <type_traits> // is_rvalue_reference, is_trivially_destructible

#include <iostream> // cout, endl ============================= REMOVE THIS
using std::cerr, std::cout, std::endl;

#include <unistd.h> // lseek, read, close
#include <fcntl.h> // open

char *GetStackBottom(void) noexcept
{ static thread_local int fd = -1;

if ( fd < 0 )
{
fd = ::open("/proc/thread-self/maps", O_RDONLY);

if ( fd < 0 ) return nullptr;

// std::atexit( [](){ ::close(fd); } ); - Won't work
}

if ( 0 != ::lseek(fd, 0, SEEK_SET) ) return nullptr;

static char buf[8192u];
if ( ::read(fd, buf, 8191u) < 32 ) return nullptr;
buf[8191u] = '\0';

char *vm = std::strstr(buf, "[stack]\n");
if ( nullptr == vm ) return nullptr;

while ( '\n' != *vm ) --vm;

++vm;

while ( '-' != *vm ) ++vm;

char *vm2 = ++vm;

while ( ' ' != *vm2 ) ++vm2;

*vm2 = '\0';

static_assert( ULONG_LONG_MAX >= UINTPTR_MAX );
long long unsigned const addr = std::strtoull(vm,nullptr,16u);

return reinterpret_cast<char*>(addr);
}

thread_local char *p_original, *p_replacement;
thread_local void (*f)(void), (*g)(void);
thread_local char *bottom_of_stack;
thread_local std::exception_ptr e;

extern "C" {
void Assembler_set_bottom_of_stack (void) noexcept;
void Assembler_set_stack_pointer_and_invoke(void) noexcept;
}

__asm("Assembler_set_bottom_of_stack: \n"
".intel_syntax noprefix \n"
" mov r10, rsp \n"
" add r10, 16 \n" // +8 return addr, +8 to be safe
" mov QWORD PTR fs:bottom_of_stack@tpoff, r10 \n"
" ret \n"
".att_syntax");

template<typename T> requires std::is_trivially_destructible_v<std::remove_cvref_t<T> >
std::remove_cvref_t<T> dummy_prvalue(void) noexcept
{ typedef std::remove_cvref_t<T> TT;
void (*const tmp)(void) = [](){};
TT (*const funcptr)(void) = reinterpret_cast<TT(*)(void)>(tmp);
return funcptr(); // guaranteed elision of move/copy operations here
}

template<typename R, typename... Params>
class Invoker {

static R exception_capable(Params... args) noexcept
{
cerr << "Entered exception_capable\n";

R (*const funcptr)(Params...) = reinterpret_cast<R(*)(Params...)>(g);

try
{
cerr << "Entered try-block\n";
return funcptr( std::forward<Params>(args)... );
}
catch (...)
{
cerr << "Exception thrown!\n";
e = std::current_exception();
}

return dummy_prvalue<R>();
}

Invoker(char *const arg_p, R(*const arg_f)(Params...)) noexcept
{
p_replacement = arg_p; // sets a thread_local variable
g = reinterpret_cast<void (*)(void)>(arg_f); // sets a thread_local variable
f = reinterpret_cast<void (*)(void)>(exception_capable); // sets a thread_local variable
}

public:
R operator()(Params... args) noexcept(false) // This could be static function but I like operator()
{
//Assembler_set_bottom_of_stack();
//cout << "\nBottom of stack: " << (void*)bottom_of_stack << " (my own assembler)\n";
bottom_of_stack = GetStackBottom() - 8u;
//cout << "Bottom of stack: " << (void*)bottom_of_stack << " (thread-self/maps)\n";
e = nullptr;
R (*const funcptr)(Params...) = reinterpret_cast<R(*)(Params...)>(Assembler_set_stack_pointer_and_invoke);
R retval = funcptr( std::forward<Params>(args)... );
if ( nullptr != e )
{
cerr << "About to rethrow!\n";
std::rethrow_exception(e);
}
return retval;
}

friend class Stacker;
};

class Stacker {
char *p;
std::unique_ptr<char[]> mystack;

public:

Stacker(std::size_t const len) noexcept(false) // might throw bad_alloc
{
assert( len >= 128u );

mystack.reset( new char[len] );
p = mystack.get() + len - 16u;
}

Stacker(char *const arg, std::size_t const len) noexcept
{
assert( nullptr != arg );
assert( len >= 128u );

p = arg + len - 16u;
}

template<typename R, typename... Params>
Invoker<R,Params...> operator()( R(*const arg)(Params...) ) noexcept
{
return Invoker<R,Params...>(this->p, arg);
}
};

/* In the following function written in x86_64 assembler using
the System V calling convention, we can only clobber r10
and r11 because all of the other caller-saved registers
must be preserved for the 'jmp' to the target function. */

__asm("Assembler_set_stack_pointer_and_invoke:\n"
".intel_syntax noprefix \n"
// Step 1: Save the original stack pointer
" mov QWORD PTR fs:p_original@tpoff, rsp \n"
// Step 2: Retrieve the replacement stack pointer
" push r15 \n" // save to restore later
" mov r15, rsp \n" // pointer to the r15 we just pushed onto stack
" add r15, 8 \n" // sets 'r15' to top of old stack
" mov r10, QWORD PTR fs:p_replacement@tpoff \n" // sets 'r10' to top of new stack
" mov rax, QWORD PTR fs:bottom_of_stack@tpoff \n" // sets 'rax' to bottom of old stack
// Right now: R15 is the top of the old stack
// R10 is the top of the new stack
// RAX is the bottom of the old stack
// We want to do:
// while ( rax != r15 ) *r10-- = *rax--;
// Step 3: Copy the old stack to the new stack (it might contain supernumerary arguments or a big return struct)
" jmp cond \n" // Jump to condition of 'while' loop
"loop: \n" // ----<----<----<----<----
" mov r11, qword ptr [rax] \n" // |
" mov qword ptr [r10], r11 \n" // ^
" sub r10, 1 \n" // | Loop
" sub rax, 1 \n" // |
"cond: \n" // ^
" cmp rax, r15 \n" // |
" jne loop \n" // ---->---->---->---->----
" pop r15 \n" // restore original value
// Step 4: Change the stack pointer to the new stack ============================================ " mov rsp, r10 \n" // ================================================= new stack
// Step 5: Set the return address to after the 'jmp' instruction
" lea r10, [Label_Jump_Back] \n"
" add rsp, 8 \n" // This line and the next line replace the return address on the stack
" push r10 \n" // This line and the previous line replace the return address on the stack
// Step 6: Invoke the function
" jmp QWORD PTR fs:f@tpoff \n" // --- Invoke the function!
"Label_Jump_Back: \n"
// Note: The label has already been popped off the stack by the callee
// Step 7: Restore the original stack pointer
" mov rsp, QWORD PTR fs:p_original@tpoff \n"
// Step 8: Jump back to the original address
" ret \n"
".att_syntax");


Click here to read the complete article
1
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor