comp.lang.ada
 help / color / mirror / Atom feed
* Using pointers with inline assembly in Ada
@ 2022-06-09 21:30 NiGHTS
  2022-06-10  5:24 ` Rod Kay
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: NiGHTS @ 2022-06-09 21:30 UTC (permalink / raw)


I would like to write an inline assembly code in Ada that simply writes a constant to a specific element of an array of unsigned values.

I'm shooting in the dark here because there are absolutely no references on this subject, to my surprise.

This was my first experiment which produces a memory access error. In this early version I'm just trying to write to the first element.

declare
         type ff is array (0 .. 10) of Unsigned_32;
         pragma Pack(ff);
         Flags : aliased ff := (others => 0);
         Flag_Address : System.Address := Flags'Address;
begin
        Asm (   "movl %0, %%eax" &
                "movl $1, (%%eax)" ,             
                Inputs   => System.Address'Asm_Input ("g", Flag_Address),
                Clobber  => "eax",
                Volatile => true
        );
        Put_Line ("Output:" & Flags(0)'Img);
end;

Any help would be greatly appreciated!

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-09 21:30 Using pointers with inline assembly in Ada NiGHTS
@ 2022-06-10  5:24 ` Rod Kay
  2022-06-10 11:16   ` Luke A. Guest
                     ` (3 more replies)
  2022-06-10 13:39 ` Jeffrey R.Carter
                   ` (2 subsequent siblings)
  3 siblings, 4 replies; 13+ messages in thread
From: Rod Kay @ 2022-06-10  5:24 UTC (permalink / raw)


On 10/6/22 07:30, NiGHTS wrote:
> declare
>           type ff is array (0 .. 10) of Unsigned_32;
>           pragma Pack(ff);
>           Flags : aliased ff := (others => 0);
>           Flag_Address : System.Address := Flags'Address;
> begin
>          Asm (   "movl %0, %%eax" &
>                  "movl $1, (%%eax)" ,
>                  Inputs   => System.Address'Asm_Input ("g", Flag_Address),
>                  Clobber  => "eax",
>                  Volatile => true
>          );
>          Put_Line ("Output:" & Flags(0)'Img);
> end;
> 

    If you are on a 64 bit machine, then I expect 'pragma Pack' might be 
the problem, as 2 consecutive array elements will fir into a single address.


    Also, possibly use ...

    Flag_Address : System.Address := Flags (Flags'First)'Address;


Regards.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-10  5:24 ` Rod Kay
@ 2022-06-10 11:16   ` Luke A. Guest
  2022-06-10 12:26     ` NiGHTS
  2022-06-10 12:16   ` NiGHTS
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 13+ messages in thread
From: Luke A. Guest @ 2022-06-10 11:16 UTC (permalink / raw)


On 10/06/2022 06:24, Rod Kay wrote:
> On 10/6/22 07:30, NiGHTS wrote:
>> declare
>>           type ff is array (0 .. 10) of Unsigned_32;
>>           pragma Pack(ff);
>>           Flags : aliased ff := (others => 0);
>>           Flag_Address : System.Address := Flags'Address;
>> begin
>>          Asm (   "movl %0, %%eax" &
>>                  "movl $1, (%%eax)" ,
>>                  Inputs   => System.Address'Asm_Input ("g", 
>> Flag_Address),
>>                  Clobber  => "eax",
>>                  Volatile => true
>>          );
>>          Put_Line ("Output:" & Flags(0)'Img);
>> end;
>>
> 
>     If you are on a 64 bit machine, then I expect 'pragma Pack' might be 
> the problem, as 2 consecutive array elements will fir into a single 
> address.
> 
> 
>     Also, possibly use ...
> 
>     Flag_Address : System.Address := Flags (Flags'First)'Address;
> 
> 
> Regards.

Dump the xpanded (generated code) and the assembly from gnat.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-10  5:24 ` Rod Kay
  2022-06-10 11:16   ` Luke A. Guest
@ 2022-06-10 12:16   ` NiGHTS
  2022-06-10 13:19     ` Jeffrey R.Carter
       [not found]   ` <nnd$727405a5$1c8a5b81@aedbf58048bf777d>
  2022-06-11  1:43   ` Rod Kay
  3 siblings, 1 reply; 13+ messages in thread
From: NiGHTS @ 2022-06-10 12:16 UTC (permalink / raw)


On Friday, June 10, 2022 at 1:28:17 AM UTC-4, roda...@gmail.com wrote:
> On 10/6/22 07:30, NiGHTS wrote: 
> > declare 
> > type ff is array (0 .. 10) of Unsigned_32; 
> > pragma Pack(ff); 
> > Flags : aliased ff := (others => 0); 
> > Flag_Address : System.Address := Flags'Address; 
> > begin 
> > Asm ( "movl %0, %%eax" & 
> > "movl $1, (%%eax)" , 
> > Inputs => System.Address'Asm_Input ("g", Flag_Address), 
> > Clobber => "eax", 
> > Volatile => true 
> > ); 
> > Put_Line ("Output:" & Flags(0)'Img); 
> > end; 
> >
> If you are on a 64 bit machine, then I expect 'pragma Pack' might be 
> the problem, as 2 consecutive array elements will fir into a single address. 
> 
> 
> Also, possibly use ... 
> 
> Flag_Address : System.Address := Flags (Flags'First)'Address; 
> 
> 
> Regards.

Thank you for your response. Unfortunately this didn't seem to work. I agree that the pragma was misused, though that shouldn't have caused the error accessing the first element. I also am not entirely sure why there would be a difference between the address of the first element versus the address of the array itself (maybe that's just my C instincts kicking in).

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
       [not found]   ` <nnd$727405a5$1c8a5b81@aedbf58048bf777d>
@ 2022-06-10 12:23     ` NiGHTS
  0 siblings, 0 replies; 13+ messages in thread
From: NiGHTS @ 2022-06-10 12:23 UTC (permalink / raw)


On Friday, June 10, 2022 at 3:15:38 AM UTC-4, ldries46 wrote:
> Op 10-6-2022 om 7:24 schreef Rod Kay:
> On 10/6/22 07:30, NiGHTS wrote: 
> declare 
>           type ff is array (0 .. 10) of Unsigned_32; 
>           pragma Pack(ff); 
>           Flags : aliased ff := (others => 0); 
>           Flag_Address : System.Address := Flags'Address; 
> begin 
>          Asm (   "movl %0, %%eax" & 
>                  "movl $1, (%%eax)" , 
>                  Inputs   => System.Address'Asm_Input ("g", Flag_Address), 
>                  Clobber  => "eax", 
>                  Volatile => true 
>          ); 
>          Put_Line ("Output:" & Flags(0)'Img); 
> end; 
> 
> 
>    If you are on a 64 bit machine, then I expect 'pragma Pack' might be the problem, as 2 consecutive array elements will fir into a single address. 
> 
> 
>    Also, possibly use ... 
> 
>    Flag_Address : System.Address := Flags (Flags'First)'Address; 
> 
> 
> Regards.
> There maybe a a way around this problem, if there is a compiler that can create assembly code. I have used that method in the past with Pascal programs where I wanted to avoid internal checks on errors that could not occur in that part of the program.
> 
> Warning: Programming the way you want to means that your program will mean that your program can become depending on the system you are working on. Meaning for instance not only recompiling when migrating from Windows to Linux but also reprogramming that part of your work

Ada does a good job generating efficient machine code, and there are lots of ways to get around compiler checks (unlike Pascal). In this situation I was trying to make use of a very specific set of uncommon CPU instructions but required passing an array to it that allows side-effects. I'm a bit peeved that there is so little in the way of documentation for the Asm command.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-10 11:16   ` Luke A. Guest
@ 2022-06-10 12:26     ` NiGHTS
  0 siblings, 0 replies; 13+ messages in thread
From: NiGHTS @ 2022-06-10 12:26 UTC (permalink / raw)


On Friday, June 10, 2022 at 7:18:03 AM UTC-4, Luke A. Guest wrote:
> On 10/06/2022 06:24, Rod Kay wrote: 
> > On 10/6/22 07:30, NiGHTS wrote: 
> >> declare 
> >>           type ff is array (0 .. 10) of Unsigned_32; 
> >>           pragma Pack(ff); 
> >>           Flags : aliased ff := (others => 0); 
> >>           Flag_Address : System.Address := Flags'Address; 
> >> begin 
> >>          Asm (   "movl %0, %%eax" & 
> >>                  "movl $1, (%%eax)" , 
> >>                  Inputs   => System.Address'Asm_Input ("g", 
> >> Flag_Address), 
> >>                  Clobber  => "eax", 
> >>                  Volatile => true 
> >>          ); 
> >>          Put_Line ("Output:" & Flags(0)'Img); 
> >> end; 
> >> 
> > 
> >    If you are on a 64 bit machine, then I expect 'pragma Pack' might be 
> > the problem, as 2 consecutive array elements will fir into a single 
> > address. 
> > 
> > 
> >    Also, possibly use ... 
> > 
> >    Flag_Address : System.Address := Flags (Flags'First)'Address; 
> > 
> > 
> > Regards.
> Dump the xpanded (generated code) and the assembly from gnat.

Though that wouldn't be a bad idea, I've decided to do this another way. I have a limited time to work on this project and I'm just not feeling it. Too risky to work on something this important with so little documentation. I figured I'd give the problem the due-diligence of posting the question on here but I've made up my mind that at least with the project I am working on that I write the code in C/Asm instead. Thank you for your help though.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-10 12:16   ` NiGHTS
@ 2022-06-10 13:19     ` Jeffrey R.Carter
  0 siblings, 0 replies; 13+ messages in thread
From: Jeffrey R.Carter @ 2022-06-10 13:19 UTC (permalink / raw)


On 2022-06-10 14:16, NiGHTS wrote:
> 
> I also am not entirely sure why there would be a difference between the address of the first element versus the address of the array itself (maybe that's just my C instincts kicking in).

Unlike C, an Ada array has associated bounds information. Sometimes that bounds 
information is physically stored with the array data, usually before them. There 
is implementation advice that A'Address and A (A'First)'Address should give the 
same address, but some compilers return the address of the bounds information.

In your particular case, the bounds are static, so the compiler probably doesn't 
store them, and GNAT follows the implementation advice, so there is no 
difference in the two forms in any case.

-- 
Jeff Carter
"I'm a lumberjack and I'm OK."
Monty Python's Flying Circus
54

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-09 21:30 Using pointers with inline assembly in Ada NiGHTS
  2022-06-10  5:24 ` Rod Kay
@ 2022-06-10 13:39 ` Jeffrey R.Carter
  2022-06-11  1:51   ` NiGHTS
  2022-06-11 12:28 ` Simon Wright
  2022-06-13 20:33 ` Gabriele Galeotti
  3 siblings, 1 reply; 13+ messages in thread
From: Jeffrey R.Carter @ 2022-06-10 13:39 UTC (permalink / raw)


On 2022-06-09 23:30, NiGHTS wrote:
> 
> declare
>           type ff is array (0 .. 10) of Unsigned_32;
>           pragma Pack(ff);
>           Flags : aliased ff := (others => 0);
>           Flag_Address : System.Address := Flags'Address;
> begin
>          Asm (   "movl %0, %%eax" &
>                  "movl $1, (%%eax)" ,
>                  Inputs   => System.Address'Asm_Input ("g", Flag_Address),
>                  Clobber  => "eax",
>                  Volatile => true
>          );
>          Put_Line ("Output:" & Flags(0)'Img);
> end;

Have you looked at the GNAT User's Guide section on this 
(https://docs.adacore.com/live/wave/gnat_ugn/html/gnat_ugn/gnat_ugn/inline_assembler.html)? 
I have never used this, but the first thing I notice is that the examples in the 
User's Guide put an LF-HT pair between statements:

    Asm ("pushfl"          & LF & HT & -- push flags on stack
         "popl %%eax"      & LF & HT & -- load eax with flags
         "movl %%eax, %0",             -- store flags in variable
         Outputs => Unsigned_32'Asm_Output ("=g", Flags));

It is also legal to separate the statements with spaces, but what you have would 
seem to be

    movl %0, %%eaxmovl $1, (%%eax)

which may be a problem.

-- 
Jeff Carter
"I'm a lumberjack and I'm OK."
Monty Python's Flying Circus
54

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-10  5:24 ` Rod Kay
                     ` (2 preceding siblings ...)
       [not found]   ` <nnd$727405a5$1c8a5b81@aedbf58048bf777d>
@ 2022-06-11  1:43   ` Rod Kay
  3 siblings, 0 replies; 13+ messages in thread
From: Rod Kay @ 2022-06-11  1:43 UTC (permalink / raw)


On 10/6/22 15:24, Rod Kay wrote:
> On 10/6/22 07:30, NiGHTS wrote:
> 
>     If you are on a 64 bit machine, then I expect 'pragma Pack' might be 
> the problem, as 2 consecutive array elements will fir into a single 
> address.
> 

    Well, this is clearly nonsense. I don't know what I was thinking. I 
suppose I was simply *not* thinking.


*Embarrassed*

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-10 13:39 ` Jeffrey R.Carter
@ 2022-06-11  1:51   ` NiGHTS
  0 siblings, 0 replies; 13+ messages in thread
From: NiGHTS @ 2022-06-11  1:51 UTC (permalink / raw)


On Friday, June 10, 2022 at 9:39:44 AM UTC-4, Jeffrey R.Carter wrote:
> On 2022-06-09 23:30, NiGHTS wrote: 
> > 
> > declare 
> > type ff is array (0 .. 10) of Unsigned_32; 
> > pragma Pack(ff); 
> > Flags : aliased ff := (others => 0); 
> > Flag_Address : System.Address := Flags'Address; 
> > begin 
> > Asm ( "movl %0, %%eax" & 
> > "movl $1, (%%eax)" , 
> > Inputs => System.Address'Asm_Input ("g", Flag_Address), 
> > Clobber => "eax", 
> > Volatile => true 
> > ); 
> > Put_Line ("Output:" & Flags(0)'Img); 
> > end;
> Have you looked at the GNAT User's Guide section on this 
> (https://docs.adacore.com/live/wave/gnat_ugn/html/gnat_ugn/gnat_ugn/inline_assembler.html)? 
> I have never used this, but the first thing I notice is that the examples in the 
> User's Guide put an LF-HT pair between statements: 
> 
> Asm ("pushfl" & LF & HT & -- push flags on stack 
> "popl %%eax" & LF & HT & -- load eax with flags 
> "movl %%eax, %0", -- store flags in variable 
> Outputs => Unsigned_32'Asm_Output ("=g", Flags)); 
> 
> It is also legal to separate the statements with spaces, but what you have would 
> seem to be 
> 
> movl %0, %%eaxmovl $1, (%%eax) 
> 
> which may be a problem.
> -- 
> Jeff Carter 
> "I'm a lumberjack and I'm OK." 
> Monty Python's Flying Circus 
> 54
On my side I had the LF HT characters. I copied the code badly to this posting. So though you are right, my post lied a little bit by accident. This didn't end up being the main problem.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-09 21:30 Using pointers with inline assembly in Ada NiGHTS
  2022-06-10  5:24 ` Rod Kay
  2022-06-10 13:39 ` Jeffrey R.Carter
@ 2022-06-11 12:28 ` Simon Wright
  2022-06-11 12:32   ` NiGHTS
  2022-06-13 20:33 ` Gabriele Galeotti
  3 siblings, 1 reply; 13+ messages in thread
From: Simon Wright @ 2022-06-11 12:28 UTC (permalink / raw)


NiGHTS <nights@unku.us> writes:

> This was my first experiment which produces a memory access error. In
> this early version I'm just trying to write to the first element.
>
> declare
>          type ff is array (0 .. 10) of Unsigned_32;
>          pragma Pack(ff);
>          Flags : aliased ff := (others => 0);
>          Flag_Address : System.Address := Flags'Address;
> begin
>         Asm (   "movl %0, %%eax" &
>                 "movl $1, (%%eax)" ,             
>                 Inputs   => System.Address'Asm_Input ("g", Flag_Address),
>                 Clobber  => "eax",
>                 Volatile => true
>         );
>         Put_Line ("Output:" & Flags(0)'Img);
> end;

I got an access error as well (macOS, GCC 12.1.0, 64 bits).

Eventually, it turned out that the problem was that eax is a 32-bit
register. (the compiler used rdx, and the assembler told me that
movl %rdx, %eax wasn't allowed).

This is my working code; Flags is volatile, because otherwise the
compiler doesn't realise (at -O2) that Flags (0) has been touched.

ALso, note the Inputs line!

====
with System.Machine_Code; use System.Machine_Code;
with Interfaces; use Interfaces;
with Ada.Text_IO; use Ada.Text_IO;
procedure Nights is
   type Ff is array (0 .. 10) of Unsigned_32;
   Flags : aliased Ff := (others => 0) with Volatile;
begin
   Asm (
        "movq %0, %%rax" & ASCII.LF & ASCII.HT
          & "movl $1, (%%rax)",
        Inputs   => System.Address'Asm_Input ("g", Flags (Flags'First)'Address),
        Clobber  => "rax",
        Volatile => True
       );
   Put_Line ("Output:" & Flags(0)'Img);
end Nights;

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-11 12:28 ` Simon Wright
@ 2022-06-11 12:32   ` NiGHTS
  0 siblings, 0 replies; 13+ messages in thread
From: NiGHTS @ 2022-06-11 12:32 UTC (permalink / raw)


On Saturday, June 11, 2022 at 8:28:28 AM UTC-4, Simon Wright wrote:
> NiGHTS <nig...@unku.us> writes: 
> 
> > This was my first experiment which produces a memory access error. In 
> > this early version I'm just trying to write to the first element. 
> > 
> > declare 
> > type ff is array (0 .. 10) of Unsigned_32; 
> > pragma Pack(ff); 
> > Flags : aliased ff := (others => 0); 
> > Flag_Address : System.Address := Flags'Address; 
> > begin 
> > Asm ( "movl %0, %%eax" & 
> > "movl $1, (%%eax)" , 
> > Inputs => System.Address'Asm_Input ("g", Flag_Address), 
> > Clobber => "eax", 
> > Volatile => true 
> > ); 
> > Put_Line ("Output:" & Flags(0)'Img); 
> > end;
> I got an access error as well (macOS, GCC 12.1.0, 64 bits). 
> 
> Eventually, it turned out that the problem was that eax is a 32-bit 
> register. (the compiler used rdx, and the assembler told me that 
> movl %rdx, %eax wasn't allowed). 
> 
> This is my working code; Flags is volatile, because otherwise the 
> compiler doesn't realise (at -O2) that Flags (0) has been touched. 
> 
> ALso, note the Inputs line! 
> 
> ==== 
> with System.Machine_Code; use System.Machine_Code; 
> with Interfaces; use Interfaces; 
> with Ada.Text_IO; use Ada.Text_IO; 
> procedure Nights is 
> type Ff is array (0 .. 10) of Unsigned_32; 
> Flags : aliased Ff := (others => 0) with Volatile; 
> begin 
> Asm ( 
> "movq %0, %%rax" & ASCII.LF & ASCII.HT 
> & "movl $1, (%%rax)", 
> Inputs => System.Address'Asm_Input ("g", Flags (Flags'First)'Address), 
> Clobber => "rax", 
> Volatile => True
> ); 
> Put_Line ("Output:" & Flags(0)'Img);
> end Nights;
I haven't tested this yet but the solution makes sense to me. Thank you for your help!

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: Using pointers with inline assembly in Ada
  2022-06-09 21:30 Using pointers with inline assembly in Ada NiGHTS
                   ` (2 preceding siblings ...)
  2022-06-11 12:28 ` Simon Wright
@ 2022-06-13 20:33 ` Gabriele Galeotti
  3 siblings, 0 replies; 13+ messages in thread
From: Gabriele Galeotti @ 2022-06-13 20:33 UTC (permalink / raw)


On Thursday, June 9, 2022 at 11:30:21 PM UTC+2, NiGHTS wrote:
> I would like to write an inline assembly code in Ada that simply writes a constant to a specific element of an array of unsigned values. 
> 
> I'm shooting in the dark here because there are absolutely no references on this subject, to my surprise. 
> 
> This was my first experiment which produces a memory access error. In this early version I'm just trying to write to the first element. 
> 
> declare 
> type ff is array (0 .. 10) of Unsigned_32; 
> pragma Pack(ff); 
> Flags : aliased ff := (others => 0); 
> Flag_Address : System.Address := Flags'Address; 
> begin 
> Asm ( "movl %0, %%eax" & 
> "movl $1, (%%eax)" , 
> Inputs => System.Address'Asm_Input ("g", Flag_Address), 
> Clobber => "eax", 
> Volatile => true 
> ); 
> Put_Line ("Output:" & Flags(0)'Img); 
> end; 
> 
> Any help would be greatly appreciated!

Your code has no huge problems, apart generating a lot of warnings and being not decorated well.

Just make the array Volatile.

Otherwise the compiler is not able to understand that you're modifying the array,
takes that as an invariant, and prints a "0" instead of "1", optimizing everything
out away:

 type ff is array (0 .. 10) of Unsigned_32; with
   Pack => True,
  Volatile => True;

There should be no problems for 64-bit machines because the components are anyway accessed on 32-bit boundaries,
but you have to adjust register sizes, EAX cannot contain an address in x86 64-bit mode (probably you have to use RAX).

G

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-06-13 20:33 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-09 21:30 Using pointers with inline assembly in Ada NiGHTS
2022-06-10  5:24 ` Rod Kay
2022-06-10 11:16   ` Luke A. Guest
2022-06-10 12:26     ` NiGHTS
2022-06-10 12:16   ` NiGHTS
2022-06-10 13:19     ` Jeffrey R.Carter
     [not found]   ` <nnd$727405a5$1c8a5b81@aedbf58048bf777d>
2022-06-10 12:23     ` NiGHTS
2022-06-11  1:43   ` Rod Kay
2022-06-10 13:39 ` Jeffrey R.Carter
2022-06-11  1:51   ` NiGHTS
2022-06-11 12:28 ` Simon Wright
2022-06-11 12:32   ` NiGHTS
2022-06-13 20:33 ` Gabriele Galeotti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox