www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.ldc - Naked functions

reply Jack Applegame <japplegame gmail.com> writes:
Hello.
How to define a naked function on the ARM platform?

 asm {
    naked;
 }
doesn't work.
Jul 23 2018
parent reply "David Nadlinger" <code klickverbot.at> writes:
Hi Jack,

On 23 Jul 2018, at 23:06, Jack Applegame via digitalmars-d-ldc wrote:
 asm {
    naked;
 }
doesn't work.
asm {} is the x86-only DMD syntax. See https://github.com/ldc-developers/ldc/pull/2773 which adds a naked attribute; it would to great to hear whether this fits your use case. — David
Jul 23 2018
next sibling parent Jack Applegame <japplegame gmail.com> writes:
On Monday, 23 July 2018 at 23:36:01 UTC, David Nadlinger wrote:
 Hi Jack,

 On 23 Jul 2018, at 23:06, Jack Applegame via digitalmars-d-ldc 
 wrote:
 asm {
    naked;
 }
doesn't work.
asm {} is the x86-only DMD syntax. See https://github.com/ldc-developers/ldc/pull/2773 which adds a naked attribute; it would to great to hear whether this fits your use case. — David
It works. Thanks.
Jul 25 2018
prev sibling parent reply Jack Applegame <japplegame gmail.com> writes:
On Monday, 23 July 2018 at 23:36:01 UTC, David Nadlinger wrote:
 Hi Jack,

 On 23 Jul 2018, at 23:06, Jack Applegame via digitalmars-d-ldc 
 wrote:
 asm {
    naked;
 }
doesn't work.
asm {} is the x86-only DMD syntax. See https://github.com/ldc-developers/ldc/pull/2773 which adds a naked attribute; it would to great to hear whether this fits your use case. — David
There is one strange thing. Should the compiler to insert the return command for naked functions? I suppose it shouldn't. For example: naked.cpp
 __attribute__ ((naked)) int sum(int a, int b) {
     return a + b;
 }
 $ arm-none-eabi-gcc -c naked.cpp -O3 -o naked_cpp.o
 $ arm-none-eabi-objdump -d naked_cpp.o
 00000000 <_Z3sumii>:
   0:   e0800001        add     r0, r0, r1
naked.d
  naked int sum(int a, int b) {
     return a + b;
 }
 $ ldc2 -c -mtriple=thumb-none-linux-eabi -mcpu=cortex-m3 -O3 
 naked.d -of naked_d.o
 $ arm-none-eabi-objdump -d naked_d.o
 00000000 <_D5naked3sumFiiZi>:
   0:   4408            add     r0, r1
   2:   4770            bx      lr     <------- WHY???
Looks like LDC removes the prologue/epilogue, but not completely, leaving the return from function.
Jul 27 2018
next sibling parent Jack Applegame <japplegame gmail.com> writes:
 $ arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb naked.cpp -O3 -o 
 naked_cpp.o
generates
 00000000 <_Z3sumii>:
   0:   4408            add     r0, r1
   2:   bf00            nop
Jul 27 2018
prev sibling parent reply kinke <noone nowhere.com> writes:
On Friday, 27 July 2018 at 10:11:03 UTC, Jack Applegame wrote:
 There is one strange thing.
 Should  the compiler to insert the return command for naked 
 functions?
 I suppose it shouldn't.

 [...]

 Looks like LDC removes the prologue/epilogue, but not 
 completely, leaving the return from function.
In this case I'd think it has to, you're even using an explicit return statement. I'm not familiar with the ARM calling convention wrt. call/return, but gcc emitting no return seems very strange (where is it supposed to continue after the add instruction? the next function in the final binary?!). Did you test that it actually works as intended? I updated the PR yesterday, so that LDC's pro-/epilogue is excluded too, which allows the usage of params (not just in some cases like yours together with -O). [Your sample doesn't work anymore now, crashing the compiler, as it now requires __asm() and/or inlineIR() to work with params.] AFAIK, a return is required as we go through LLVM IR and not directly to the assembler (which for example allows you to write the function body in LLVM IR). Yesterday's variant probably crashes if there's no explicit return (e.g., with __asm() and a naked function returning void). I take it this is just a toy example for gcc/LDC comparison, or do you really need to omit a return instruction in real-world code?
Jul 27 2018
parent reply Jack Applegame <japplegame gmail.com> writes:
On Friday, 27 July 2018 at 17:53:51 UTC, kinke wrote:
 On Friday, 27 July 2018 at 10:11:03 UTC, Jack Applegame wrote:
 There is one strange thing.
 Should  the compiler to insert the return command for naked 
 functions?
 I suppose it shouldn't.

 [...]

 Looks like LDC removes the prologue/epilogue, but not 
 completely, leaving the return from function.
In this case I'd think it has to, you're even using an explicit return statement. I'm not familiar with the ARM calling convention wrt. call/return, but gcc emitting no return seems very strange (where is it supposed to continue after the add instruction? the next function in the final binary?!). Did you test that it actually works as intended? I updated the PR yesterday, so that LDC's pro-/epilogue is excluded too, which allows the usage of params (not just in some cases like yours together with -O). [Your sample doesn't work anymore now, crashing the compiler, as it now requires __asm() and/or inlineIR() to work with params.] AFAIK, a return is required as we go through LLVM IR and not directly to the assembler (which for example allows you to write the function body in LLVM IR). Yesterday's variant probably crashes if there's no explicit return (e.g., with __asm() and a naked function returning void).
My example is incorrect. Actually, GCC documentation recommends to use only basic assembly in naked functions and Clang completely disallows the use of anything other than asm statement. But both remove the return instruction. Compare: https://godbolt.org/g/yVzpPx https://godbolt.org/g/fe9pNY
 I take it this is just a toy example for gcc/LDC comparison, or 
 do you really need to omit a return instruction in real-world 
 code?
I'm trying to write a simple kernel with multithreading support on bare metal (Cortex-M3). In the context switching function, the compiler-inserted return is unnecessary, but not a problem.
Jul 27 2018
parent reply Jack Applegame <japplegame gmail.com> writes:
This code

 import ldc.llvmasm;
  naked void foo() {
   __asm("mov lr, 0xfffffffd", "");
 }
Definitely should compile to

But now it compiles to

 bx      lr
Jul 27 2018
parent reply kinke <noone nowhere.com> writes:
On Friday, 27 July 2018 at 19:34:49 UTC, Jack Applegame wrote:
 This code

 import ldc.llvmasm;
  naked void foo() {
   __asm("mov lr, 0xfffffffd", "");
 }
Definitely should compile to

But now it compiles to

 bx      lr
'Now' (current/yesterday's PR), this crashes the compiler for the aforementioned reason. Interestingly, clang also goes through IR (see -emit-llvm and compare with LDC's -output-ll output) but appends an unreachable at the end, which gets rid of the error about non-terminated function. I've just implemented this, but the unreachable makes it to the final assembly, whereas it vanishes at some point for clang.
Jul 27 2018
parent reply kinke <noone nowhere.com> writes:
On Friday, 27 July 2018 at 20:17:12 UTC, kinke wrote:
 I've just implemented this, but the unreachable makes it to the 
 final assembly, whereas it vanishes at some point for clang.
Ah wait, that remaining unreachable is apparently Windows-specific and vanishes for Linux.
Jul 27 2018
parent Jack Applegame <japplegame gmail.com> writes:
On Friday, 27 July 2018 at 20:28:11 UTC, kinke wrote:
 On Friday, 27 July 2018 at 20:17:12 UTC, kinke wrote:
 I've just implemented this, but the unreachable makes it to 
 the final assembly, whereas it vanishes at some point for 
 clang.
Ah wait, that remaining unreachable is apparently Windows-specific and vanishes for Linux.
Good work, thank you.
Jul 27 2018