Rocksolid Light

Welcome to novaBBS (click a section below)

mail  files  register  newsreader  groups  login

Message-ID:  

Linux is obsolete -- Andrew Tanenbaum


devel / comp.unix.programmer / aarch64 - 64-Bit ARM - return by value - GNU gcc assembler

SubjectAuthor
* aarch64 - 64-Bit ARM - return by value - GNU gcc assemblerFrederick Gotham
+- aarch64 - 64-Bit ARM - return by value - GNU gcc assemblerFrederick Gotham
`* aarch64 - 64-Bit ARM - return by value - GNU gcc assemblerAdam Sampson
 `* aarch64 - 64-Bit ARM - return by value - GNU gcc assemblerFrederick Gotham
  `- aarch64 - 64-Bit ARM - return by value - GNU gcc assemblerFrederick Gotham

1
aarch64 - 64-Bit ARM - return by value - GNU gcc assembler

<e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=10794&group=comp.unix.programmer#10794

  copy link   Newsgroups: comp.unix.programmer
X-Received: by 2002:a05:622a:89:b0:403:b1f4:5dac with SMTP id o9-20020a05622a008900b00403b1f45dacmr84544qtw.9.1689603768297;
Mon, 17 Jul 2023 07:22:48 -0700 (PDT)
X-Received: by 2002:a05:6808:f0a:b0:3a4:2943:8f7 with SMTP id
m10-20020a0568080f0a00b003a4294308f7mr16287684oiw.5.1689603768053; Mon, 17
Jul 2023 07:22:48 -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.unix.programmer
Date: Mon, 17 Jul 2023 07:22:47 -0700 (PDT)
Injection-Info: google-groups.googlegroups.com; posting-host=194.168.183.164; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 194.168.183.164
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com>
Subject: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler
From: cauldwel...@gmail.com (Frederick Gotham)
Injection-Date: Mon, 17 Jul 2023 14:22:48 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 3555
 by: Frederick Gotham - Mon, 17 Jul 2023 14:22 UTC

I'm trying to write a very simple function in two or three aarch64 instructions as 'inline assembler' inside a C++ source file.

With the aarch64 calling convention on Linux, if a function returns a very large struct by value, then the address of where to store the return value is passed in the X8 register. This is out of the ordinary as far as calling conventions go. Every other calling convention, for example System V x86_64, Microsoft x64, cdecl, stdcall, arm32, pass the address of the return value in the first parameter. So for example with x86_64 on Linux, the RDI register contains the address of where to store the very large struct.

I want to try emulate this behaviour on aarch64 on Linux. When my assembler function is entered, I want it to do two things:
(1) Put the address of the indirect return object into the first parameter register, i.e. move X8 to X0
(2) Jump to a location specified by a global function pointer

So here's how I think my assembler function should look:

__asm("Invoke: \n"
" mov x0, x8 \n" // move return value address into 1st parameter
" mov x9, f \n" // Load address of code into register
" br x9 \n" // Jump to code
);

I don't know what's wrong here but it doesn't work. In the following complete C++ program, I use the class 'std::mutex' as it's a good example of a class that can't be copied or moved (I am relying on mandatory Return Value Optimisation).

Here is my entire program in one C++ file, could someone please help me write the assembler function properly? Am I supposed to be using the ADRP and LDR instructions instead of MOV?

#include <mutex> // mutex
#include <iostream> // cout, endl
using std::cout, std::endl;

void (*f)(void) = nullptr;

extern "C" void Invoke(void);

__asm("Invoke: \n"
" mov x0, x8 \n" // move return value address into 1st parameter
" mov x9, f \n" // Load address of code into register
" br x9 \n" // Jump to code
);

void Func(std::mutex *const p)
{ cout << "Address of return value: " << p << endl;
}

int main(void)
{ f = (void(*)(void))Func;

auto const p = reinterpret_cast<std::mutex (*)(void)>(Invoke);

auto retval = p();

cout << "Address of return value: " << &retval << endl;
}

Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler

<ce6b1759-72dd-4d9c-be5a-5980532eb85bn@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=10795&group=comp.unix.programmer#10795

  copy link   Newsgroups: comp.unix.programmer
X-Received: by 2002:a05:620a:1713:b0:767:15f4:7a81 with SMTP id az19-20020a05620a171300b0076715f47a81mr68079qkb.10.1689613171415;
Mon, 17 Jul 2023 09:59:31 -0700 (PDT)
X-Received: by 2002:a05:6808:2383:b0:3a4:316f:37cd with SMTP id
bp3-20020a056808238300b003a4316f37cdmr14554521oib.5.1689613171083; Mon, 17
Jul 2023 09:59:31 -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.unix.programmer
Date: Mon, 17 Jul 2023 09:59:30 -0700 (PDT)
In-Reply-To: <e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.190.201; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.190.201
References: <e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <ce6b1759-72dd-4d9c-be5a-5980532eb85bn@googlegroups.com>
Subject: Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler
From: cauldwel...@gmail.com (Frederick Gotham)
Injection-Date: Mon, 17 Jul 2023 16:59:31 +0000
Content-Type: text/plain; charset="UTF-8"
X-Received-Bytes: 1802
 by: Frederick Gotham - Mon, 17 Jul 2023 16:59 UTC

On Monday, July 17, 2023, Frederick Gotham wrote:

> __asm("Invoke: \n"
> " mov x0, x8 \n" // move return value address into 1st parameter
> " mov x9, f \n" // Load address of code into register
> " br x9 \n" // Jump to code
> );

Instead of using "inline assembler" inside a C++ source file, I instead tried to make a separate assembler file.

Here's what I have, but it still doesn't work, it's still segfaulting inside 'detail_Invoke':

..text

..global tl_p
..Addr_tl_p:
.xword tl_p

..global detail_Invoke
detail_Invoke:
adrp x9, [.Addr_tl_p]
ldr x9, [x9]
mov x10, x9
br x10

Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler

<y2aedl6e96q.fsf@offog.org>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=10796&group=comp.unix.programmer#10796

  copy link   Newsgroups: comp.unix.programmer
Path: i2pn2.org!i2pn.org!weretis.net!feeder8.news.weretis.net!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail
From: ats...@offog.org (Adam Sampson)
Newsgroups: comp.unix.programmer
Subject: Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler
Date: Mon, 17 Jul 2023 18:31:41 +0100
Lines: 39
Message-ID: <y2aedl6e96q.fsf@offog.org>
References: <e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain
X-Trace: individual.net /ukKjWM1WAevPDM2FoR1+QscoUFcpNZ41jSPg+hOAl0GgXUC6i
X-Orig-Path: cartman.offog.org!not-for-mail
Cancel-Lock: sha1:eOHA/oQl0x6uwCE9uOpnDHSC7sI= sha1:GW09LKN9rInzIYanUlIzkgqak6o= sha256:gtlEC/QtqTM1uRrffG+UHV/6DzScNhI+aVbheyq2Ptg=
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.2 (gnu/linux)
 by: Adam Sampson - Mon, 17 Jul 2023 17:31 UTC

Frederick Gotham <cauldwell.thomas@gmail.com> writes:

> So here's how I think my assembler function should look:
> __asm("Invoke: \n"
> " mov x0, x8 \n" // move return value address into 1st parameter
> " mov x9, f \n" // Load address of code into register
> " br x9 \n" // Jump to code
> );

Stepping through your program under gdb finds a couple of problems...

If you compile the program with -save-temps and look at the resulting
assembly, you'll see that your inline assembler in global isn't ending
up in the code section of the executable -- it's in .bss rather than
..text. The result of this is that when you set p in main, it's not
getting the right address, so your function's not getting reached at
all. Normally you'd use inline assembler within a function; adding .text
to the top of your code here works as a bodge.

You're right in thinking that mov won't work to get the address of
f. mov with a constant only supports small constant values (there are
only so many bits spare in a fixed-size ARM instruction), and in a
position-independent executable (the norm these days) f doesn't have a
fixed address at compile time anyway. You can use adr to compute the
address relative to pc; you then need a load instruction to read the
value stored in f, giving you the address to jump to.

This version seems to behave the way you wanted:

__asm(".text\n"
"Invoke:\n"
" mov x0, x8\n"
" adr x9, f\n"
" ldr x9, [x9]\n"
" br x9\n"
);

--
Adam Sampson <ats@offog.org> <http://offog.org/>

Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler

<ed5fa4c8-fc4d-4fc8-bf66-cd917243c276n@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=10797&group=comp.unix.programmer#10797

  copy link   Newsgroups: comp.unix.programmer
X-Received: by 2002:a05:6214:8e7:b0:634:f275:302c with SMTP id dr7-20020a05621408e700b00634f275302cmr68673qvb.5.1689628686528;
Mon, 17 Jul 2023 14:18:06 -0700 (PDT)
X-Received: by 2002:a05:6808:1814:b0:3a4:744:e91b with SMTP id
bh20-20020a056808181400b003a40744e91bmr15407379oib.0.1689628686267; Mon, 17
Jul 2023 14:18:06 -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.unix.programmer
Date: Mon, 17 Jul 2023 14:18:06 -0700 (PDT)
In-Reply-To: <y2aedl6e96q.fsf@offog.org>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.183.97; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.183.97
References: <e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com> <y2aedl6e96q.fsf@offog.org>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <ed5fa4c8-fc4d-4fc8-bf66-cd917243c276n@googlegroups.com>
Subject: Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler
From: cauldwel...@gmail.com (Frederick Gotham)
Injection-Date: Mon, 17 Jul 2023 21:18:06 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 2616
 by: Frederick Gotham - Mon, 17 Jul 2023 21:18 UTC

On Monday, July 17, 2023 at 6:45:07 PM UTC+1, Adam Sampson wrote:
>
> This version seems to behave the way you wanted:
>
> __asm(".text\n"
> "Invoke:\n"
> " mov x0, x8\n"
> " adr x9, f\n"
> " ldr x9, [x9]\n"
> " br x9\n"
> );

Thank you so much... works if I change x0 to x1 (because the 'this' pointer for a member function call goes in x0, and so my first parameter goes in x1).

For the sake of posting to this newsgroup, I simplified my problem just a tiny bit. Previously I told you that 'f' was a global variable defined as follows:

void (*f)(void);

but in actual fact it's:

thread_local void (*f)(void);

If I change it to thread_local then try to re-compile, I get a linker error:

R_AARCH64_ADR_PREL_LO21 used with TLS symbol f

Do you know what syntax I use to access the thread_local variable from assembler? Will I need to write a separate function as follows?

void (*getf(void))(void)
{
return f;
}

and then call that function from my assembler? I'm worried about corrupting the caller-saved registers, because I perform a 'br' rather than a 'blr' (i.e. I perform a jump rather than a function call). I suppose I could push and pop all the caller-saved registers before invoking 'getf'... which I know how to do on x86_64 but I'm net to all this aarch64 stuff.

Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler

<9bc9421f-9658-4d45-b8e9-7b61fee9c959n@googlegroups.com>

  copy mid

https://www.novabbs.com/devel/article-flat.php?id=10798&group=comp.unix.programmer#10798

  copy link   Newsgroups: comp.unix.programmer
X-Received: by 2002:a05:622a:1713:b0:403:b888:fa29 with SMTP id h19-20020a05622a171300b00403b888fa29mr82676qtk.0.1689677713330;
Tue, 18 Jul 2023 03:55:13 -0700 (PDT)
X-Received: by 2002:a05:6808:30a5:b0:3a3:8466:ee55 with SMTP id
bl37-20020a05680830a500b003a38466ee55mr20898523oib.8.1689677712995; Tue, 18
Jul 2023 03:55:12 -0700 (PDT)
Path: i2pn2.org!i2pn.org!weretis.net!feeder6.news.weretis.net!newsfeed.hasname.com!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.unix.programmer
Date: Tue, 18 Jul 2023 03:55:12 -0700 (PDT)
In-Reply-To: <ed5fa4c8-fc4d-4fc8-bf66-cd917243c276n@googlegroups.com>
Injection-Info: google-groups.googlegroups.com; posting-host=92.40.182.157; posting-account=w4UqJAoAAAAYC-PItfDbDoVGcg0yISyA
NNTP-Posting-Host: 92.40.182.157
References: <e8f6559c-c58b-4d26-a393-f8183ef30eefn@googlegroups.com>
<y2aedl6e96q.fsf@offog.org> <ed5fa4c8-fc4d-4fc8-bf66-cd917243c276n@googlegroups.com>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <9bc9421f-9658-4d45-b8e9-7b61fee9c959n@googlegroups.com>
Subject: Re: aarch64 - 64-Bit ARM - return by value - GNU gcc assembler
From: cauldwel...@gmail.com (Frederick Gotham)
Injection-Date: Tue, 18 Jul 2023 10:55:13 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 3308
 by: Frederick Gotham - Tue, 18 Jul 2023 10:55 UTC

On Monday, July 17, 2023 at 10:18:09 PM UTC+1, Frederick Gotham wrote:
>
> If I change it to thread_local then try to re-compile, I get a linker error:
>
> R_AARCH64_ADR_PREL_LO21 used with TLS symbol f
>
> Do you know what syntax I use to access the thread_local variable from assembler? Will I need to write a separate function as follows?

In order to try understand how thread_local variables are accessed from aarch64 assembler, I wrote the following dynamic shared library in C:

__thread void (*f)(void);

void (*g)(void);

void Func(void)
{
g = f;
}

I compiled this to 'libtest.so" and then used 'objdump' on it to see:

<Func>:
Line 01: stp x29, x30, [sp, #-16]!
Line 02: mrs x1, tpidr_el0
Line 03: mov x29, sp
Line 04: adrp x0, 20000 <__cxa_finalize>
Line 05: ldr x2, [x0, #16]
Line 06: add x0, x0, #0x10
Line 07: blr x2
Line 08: adrp x2, 1f000 <__FRAME_END__+0x1e8c8>
Line 09: ldr x2, [x2, #4032]
Line 10: ldr x0, [x1, x0]
Line 11: str x0, [x2]
Line 12: ldp x29, x30, [sp], #16
Line 13: ret

Line #2 appears to put the address of "thread local storage" inside the x1 register.
Lines #4-7 at first glance seem to call the function "__cxz_finalize" (which is the one that gets called at the end of a program to invoke all the destructors of global objects)... but really I just think that the number 0x20000 is being used as a base address to apply offsets to.
Lines #7 definitely is calling some function though, I don't know which one..
Lines #8-12, I'm not sure here... but I think they're moving the value of the thread_local variable 'f' into the global variable 'g'.

Can anyone please help me understand this? And explore how I would go about writing aarch64 to access a thread_local variable called 'f'?

1
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor