Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using pointers with inline assembly in Ada

100 views
Skip to first unread message

NiGHTS

unread,
Jun 9, 2022, 5:30:21 PM6/9/22
to
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!

Rod Kay

unread,
Jun 10, 2022, 1:28:17 AM6/10/22
to
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.

ldries46

unread,
Jun 10, 2022, 3:15:38 AM6/10/22
to
Op 10-6-2022 om 7:24 schreef Rod Kay:
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

Luke A. Guest

unread,
Jun 10, 2022, 7:18:03 AM6/10/22
to
Dump the xpanded (generated code) and the assembly from gnat.

NiGHTS

unread,
Jun 10, 2022, 8:16:42 AM6/10/22
to
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).

NiGHTS

unread,
Jun 10, 2022, 8:23:54 AM6/10/22
to
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.

NiGHTS

unread,
Jun 10, 2022, 8:26:58 AM6/10/22
to
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.

Jeffrey R.Carter

unread,
Jun 10, 2022, 9:19:32 AM6/10/22
to
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

Jeffrey R.Carter

unread,
Jun 10, 2022, 9:39:44 AM6/10/22
to
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.

Rod Kay

unread,
Jun 10, 2022, 9:47:39 PM6/10/22
to
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*

NiGHTS

unread,
Jun 10, 2022, 9:51:04 PM6/10/22
to
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.

Simon Wright

unread,
Jun 11, 2022, 8:28:28 AM6/11/22
to
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;

NiGHTS

unread,
Jun 11, 2022, 8:32:35 AM6/11/22
to
I haven't tested this yet but the solution makes sense to me. Thank you for your help!

Gabriele Galeotti

unread,
Jun 13, 2022, 4:33:16 PM6/13/22
to
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

0 new messages