• Using pointers with inline assembly in Ada

    From NiGHTS@21:1/5 to All on Thu Jun 9 14:30:18 2022
    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!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rod Kay@21:1/5 to NiGHTS on Fri Jun 10 15:24:35 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From ldries46@21:1/5 to All on Fri Jun 10 09:15:33 2022
    This is a multi-part message in MIME format.
    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
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
    <div class="moz-cite-prefix">Op 10-6-2022 om 7:24 schreef Rod Kay:<br>
    </div>
    <blockquote type="cite" cite="mid:t7ukpe$759$1@dont-email.me">On
    10/6/22 07:30, NiGHTS wrote:
    <br>
    <blockquote type="cite">declare
    <br>
              type ff is array (0 .. 10) of Unsigned_32;
    <br>
              pragma Pack(ff);
    <br>
              Flags : aliased ff := (others =&gt; 0);
    <br>
              Flag_Address : System.Address := Flags'Address;
    <br>
    begin
    <br>
             Asm (   "movl %0, %%eax" &amp;
    <br>
                     "movl $1, (%%eax)" ,
    <br>
                     Inputs   =&gt; System.Address'Asm_Input ("g",
    Flag_Address),
    <br>
                     Clobber  =&gt; "eax",
    <br>
                     Volatile =&gt; true
    <br>
             );
    <br>
             Put_Line ("Output:" &amp; Flags(0)'Img);
    <br>
    end;
    <br>
    <br>
    </blockquote>
    <br>
       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.
    <br>
    <br>
    <br>
       Also, possibly use ...
    <br>
    <br>
       Flag_Address : System.Address := Flags (Flags'First)'Address;
    <br>
    <br>
    <br>
    Regards.
    <br>
    </blockquote>
    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.<br>
    <br>
    <b>Warning: </b>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<br>
    </body>
    </html>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Luke A. Guest@21:1/5 to Rod Kay on Fri Jun 10 12:16:27 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NiGHTS@21:1/5 to Luke A. Guest on Fri Jun 10 05:26:56 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NiGHTS@21:1/5 to All on Fri Jun 10 05:23:52 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NiGHTS@21:1/5 to roda...@gmail.com on Fri Jun 10 05:16:40 2022
    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).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jeffrey R.Carter@21:1/5 to NiGHTS on Fri Jun 10 15:19:30 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jeffrey R.Carter@21:1/5 to NiGHTS on Fri Jun 10 15:39:41 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NiGHTS@21:1/5 to Jeffrey R.Carter on Fri Jun 10 18:51:02 2022
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rod Kay@21:1/5 to Rod Kay on Sat Jun 11 11:43:59 2022
    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*

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From NiGHTS@21:1/5 to Simon Wright on Sat Jun 11 05:32:33 2022
    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!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Simon Wright@21:1/5 to NiGHTS on Sat Jun 11 13:28:24 2022
    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;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Gabriele Galeotti@21:1/5 to NiGHTS on Mon Jun 13 13:33:14 2022
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)