❌ About FreshRSS

Reading view

There are new articles available, click to refresh the page.

Segmentation fault in Ada inline assembler [duplicate]

I'm taking my first steps in Ada and attempting to write a package which manipulates the CPUID instruction. I found some sequences on the OSDev wiki here for checking the EFLAGS.ID bit that I'm attempting to modify into an Ada function using inline assembler, but I'm running into a persistent segfault when trying to run it. First, the package spec & body:

-- Specification file: Cpuid.ads --

with Standard_Types; use Standard_Types;

package Cpuid is
    
    function Is_Supported return Boolean;

end Cpuid;

-- Body file: Cpuid.adb --

with System.Machine_Code; use System.Machine_Code;

package body Cpuid is

    function Is_Supported return Boolean is
        HT  : constant Character := Character'Val(16#09#);
        LF  : constant Character := Character'Val(16#0A#);
        EAX : Unsigned_32 := 16#0000_0000#;
    begin
        Asm ("pushfq"                    & LF & HT &
             "pushfq"                    & LF & HT &
             "popq    %%rax"             & LF & HT &
             "xorq    0x00200000, %%rax" & LF & HT &
             "pushq   %%rax"             & LF & HT &
             "popfq"                     & LF & HT &
             "pushfq"                    & LF & HT &
             "popq    %%rax"             & LF & HT &
             "xorq    (%%rsp), %%rax"    & LF & HT &
             "popfq"                     & LF & HT &
             "andq    0x00200000, %%rax" & LF & HT &
             "movl    %%eax, %0",
             Outputs  => Unsigned_32'Asm_Output ("=g", EAX),
             Volatile => True);
        if EAX /= 16#0000_0000# then 
            return True; 
        else 
            return False; 
        end if;
    end Is_Supported;

end Cpuid;

The Cpuid.Is_Supported function is called by a main program which looks like this:

with Ada.Text_IO;    use Ada.Text_IO;
with Standard_Types; use Standard_Types;
with Cpuid;

procedure Cpuid_Check is
    Some_Int : Unsigned_32 := 0;
begin
    if Cpuid.Is_Supported then
        Put_Line ("CPUID instruction supported on this CPU.");
    else
        Put_Line ("CPUID instruction not supported.");
    end if;
end Cpuid_Check;

Note that the Standard_Types import is just a spec-only package consisting of handwritten type definitions for Unsigned_8, Unsigned_16, and Unsigned_32.

When I attempt to run this program, the program fails with PROGRAM_ERROR : EXCEPTION_ACCESS_VIOLATION. Using GDB allows me to trace the error to a SIGSEGV, but I am not able to trace the violation further to a particular instruction issuance. The full debugger output is as follows:

Temporary breakpoint 14, 0x00000000004016e0 in cpuid_check ()
[program stopped: breakpoint-hit]
(gdb) -exec-next
Single stepping until exit from function _ada_cpuid_check,
which has no line number information.
[program running]

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401ede in cpuid.is_supported ()
[program stopped: signal-received]
(gdb) -exec-next
Single stepping until exit from function cpuid__is_supported,
which has no line number information.
[program running]

Program received signal SIGSEGV, Segmentation fault.
0x00007ffc4d3473f9 in KERNEL32!IsBadReadPtr () from C:\Windows\System32\kernel32.dll
[program stopped: signal-received]
(gdb) 

I've checked to ensure that I'm leaving the stack "as I found it", which, to the best of my ability, appears to be the case - the same number of pushes and pops occur within the inline assembly section. I've also rearranged the assembly sequence into src, dest format, as my reading on GAS indicates that is the syntax used. In the process, however, I bamboozled myself - I'm more used to Intel/NASM syntax, and GAS looks like a mess in comparison.

Is there a way to rectify this function so that it functions properly?

EDIT: Here is the disassembly dump from GDB, as noted in the comments:

(gdb) disas
Dump of assembler code for function cpuid__is_supported:
   0x0000000000401ec4 <+0>: push   %rbp
   0x0000000000401ec5 <+1>: mov    %rsp,%rbp
   0x0000000000401ec8 <+4>: sub    $0x10,%rsp
   0x0000000000401ecc <+8>: movb   $0x9,-0x1(%rbp)
   0x0000000000401ed0 <+12>:    movb   $0xa,-0x2(%rbp)
   0x0000000000401ed4 <+16>:    movl   $0x0,-0x8(%rbp)
   0x0000000000401edb <+23>:    pushfq 
   0x0000000000401edc <+24>:    pushfq 
   0x0000000000401edd <+25>:    pop    %rax
=> 0x0000000000401ede <+26>:    xor    0x200000,%rax
   0x0000000000401ee6 <+34>:    push   %rax
   0x0000000000401ee7 <+35>:    popfq  
   0x0000000000401ee8 <+36>:    pushfq 
   0x0000000000401ee9 <+37>:    pop    %rax
   0x0000000000401eea <+38>:    xor    (%rsp),%rax
   0x0000000000401eee <+42>:    popfq  
   0x0000000000401eef <+43>:    and    0x200000,%rax
   0x0000000000401ef7 <+51>:    mov    %eax,%eax
   0x0000000000401ef9 <+53>:    mov    %eax,-0x8(%rbp)
   0x0000000000401efc <+56>:    cmpl   $0x0,-0x8(%rbp)
   0x0000000000401f00 <+60>:    je     0x401f09 <cpuid__is_supported+69>
   0x0000000000401f02 <+62>:    mov    $0x1,%eax
   0x0000000000401f07 <+67>:    jmp    0x401f0e <cpuid__is_supported+74>
   0x0000000000401f09 <+69>:    mov    $0x0,%eax
   0x0000000000401f0e <+74>:    nop
   0x0000000000401f0f <+75>:    nop
   0x0000000000401f10 <+76>:    add    $0x10,%rsp
   0x0000000000401f14 <+80>:    pop    %rbp
   0x0000000000401f15 <+81>:    retq   
   0x0000000000401f16 <+82>:    nop
   0x0000000000401f17 <+83>:    nop
   0x0000000000401f18 <+84>:    nop
   0x0000000000401f19 <+85>:    nop
   0x0000000000401f1a <+86>:    nop
   0x0000000000401f1b <+87>:    nop
   0x0000000000401f1c <+88>:    nop
   0x0000000000401f1d <+89>:    nop
   0x0000000000401f1e <+90>:    nop
   0x0000000000401f1f <+91>:    nop
End of assembler dump.

Ada2012: Assertion_Policy

According Ada2012 RM Assertion_Policy:

10.2/3 A pragma Assertion_Policy applies to the named assertion aspects in a specific region, and applies to all assertion expressions specified in that region. A pragma Assertion_Policy given in a declarative_part or immediately within a package_specification applies from the place of the pragma to the end of the innermost enclosing declarative region. The region for a pragma Assertion_Policy given as a configuration pragma is the declarative region for the entire compilation unit (or units) to which it applies.

This means that if I have a package hierarchy as per the following example:

└───Root
    β”œβ”€β”€β”€Child1
    β”œβ”€β”€β”€Child2
    β”‚   └───GrandSon
    └───Child3

And if I define the pragma Assertion_Policy at Root package specification, it will affect to the whole package hierarchy right?

Ada instanciation of a generic package with an implementation of a limited interface

I have a limited interface defined in my_interface_package.ads.

package My_Interface_Package is

   type My_Interface is limited interface;

   procedure Procedure_1 (Some_Parameter : in out My_Interface) is null;
   procedure Procedure_2 (Some_Parameter_1 : in out My_Interface; Some_Parameter_2 : in String) is abstract;

end My_Interface_Package;

The type My_Class implements this interface (in my_class_package.ads and my_class_package.adb).

with My_Interface_Package;

package My_Class_Package is

   type My_Class is limited new My_Interface_Package.My_Interface with record
      Some_Element : Boolean;
   end record;

   overriding procedure Procedure_1 (Some_Parameter : in out My_Class);
   overriding procedure Procedure_2 (Some_Parameter_1 : in out My_Class; Some_Parameter_2 : in String);

end My_Class_Package;
with Ada.Text_IO;

package body My_Class_Package is

   procedure Procedure_1 (Some_Parameter : in out My_Class) is
   begin
      Ada.Text_IO.Put_Line("Inside Procedure_1.");
   end;

   procedure Procedure_2 (Some_Parameter_1 : in out My_Class; Some_Parameter_2 : in String) is
   begin
      Ada.Text_IO.Put_Line("Inside Procedure_2.");
   end;

end My_Class_Package;

I have a generic package My_Generic_Package defined in my_generic_package.ads and my_generic_package.adb. It expects a type My_Generic_Type. I want this type to accept any concrete implementation of the interface My_Interface.

with My_Interface_Package;

generic
   type My_Generic_Type is limited new My_Interface_Package.My_Interface with private; -- The problem seems to be in this declaration.
package My_Generic_Package is

   type My_Generic_Class is record
      Element : My_Generic_Type;
   end record;

   procedure Calling_Procedure_1 (Some_Parameter : in out My_Generic_Class);
   procedure Calling_Procedure_2 (Some_Parameter_1 : in out My_Generic_Class; Some_Parameter_2 : in String);

end My_Generic_Package;
with Ada.Text_IO;

package body My_Generic_Package is

   procedure Calling_Procedure_1 (Some_Parameter : in out My_Generic_Class) is
   begin
      Ada.Text_IO.Put_Line("Calling Procedure_1.");
      Procedure_1(Some_Parameter);
   end;

   procedure Calling_Procedure_2 (Some_Parameter_1 : in out My_Generic_Class; Some_Parameter_2 : in String) is
   begin
      Ada.Text_IO.Put_Line("Calling Procedure_2.");
      Procedure_2(Some_Parameter_1, Some_Parameter_2);
   end;

end My_Generic_Package;

My main.adb:

with Ada.Text_IO;
with My_Class_Package;
with My_Generic_Package;

procedure Main is
   package My_Instanciated_Package is new My_Generic_Package(My_Generic_Type => My_Class_Package.My_Class);
   My_Object : My_Instanciated_Package.My_Generic_Class;
begin
   My_Instanciated_Package.Calling_Procedure_1(My_Object);
   My_Instanciated_Package.Calling_Procedure_2(My_Object, "some_string");
   Ada.Text_IO.Put_Line("Program terminated.");
end Main;

GNAT 12.2.0 tells me my_generic_package.ads:3:73: missing ";" (he doesn't want the 'with private' part, but even without it, also fail).

I have tried a bunch of other declaration but ultimatly (trying to inspire myself from wikibooks), all failed. Any idea of what's wrong ?

Stack corruption in Ada C binding to OpenGL function

I'm using SDL to retrieve the address of the function. That much seems to be working, since I'm using the same subprogram that's working for all my other function calls.

Here are all the relevant code snippits in the spec:

type GLenum is new Uint32;

subtype glTexImage2D_Target is GLenum with Static_Predicate => glTexImage2D_Target in GL_TEXTURE_2D | GL_TEXTURE_RECTANGLE | GL_PROXY_TEXTURE_RECTANGLE;
subtype glTexImage2D_Dtype is GLenum with Static_Predicate => glTexImage2D_Dtype in GL_BYTE | GL_UNSIGNED_BYTE;
subtype glTexImage2D_InternalFormat is GLenum with Static_Predicate => glTexImage2D_InternalFormat in GL_DEPTH_COMPONENT | GL_DEPTH_STENCIL | GL_RED | GL_RG | GL_RGB | GL_RGBA;
subtype glTexImage2D_Format is GLenum with Static_Predicate => glTexImage2D_Format in GL_RED | GL_RG | GL_RGB | GL_BGR | GL_RGBA | GL_BGRA | GL_RED_INTEGER | GL_RG_INTEGER | GL_RGB_INTEGER | GL_BGR_INTEGER | GL_RGBA_INTEGER | GL_BGRA_INTEGER | GL_STENCIL_INDEX | GL_DEPTH_COMPONENT | GL_DEPTH_STENCIL;

procedure glTexImage2D(target : glTexImage2D_Target; level : Integer; internalFormat : glTexImage2D_InternalFormat; width : Integer; height : Integer; format : glTexImage2D_Format; dtype : glTexImage2D_Dtype; pixels : System.Address) with Pre => (target /= GL_TEXTURE_RECTANGLE and target /= GL_PROXY_TEXTURE_RECTANGLE) or Level = 0;

procedure Set_OpenGL_Subprogram_Address(Addr : in out System.Address; Name : String);

glTexImage2D_C_Address : System.Address := System.Null_Address;

Could_Not_Load_OpenGL_Subprogram : exception;

And here are the relevant snippits in the body:

procedure glTexImage2D(target : glTexImage2D_Target; level : Integer; internalFormat : glTexImage2D_InternalFormat; width : Integer; height : Integer; format : glTexImage2D_Format; dtype : glTexImage2D_Dtype; pixels : System.Address) is
begin
    Set_OpenGL_Subprogram_Address(glTexImage2D_C_Address, "glTexImage2D");
    declare
        procedure glTexImage2D_C(target : GLenum; level : GLint; internalFormat : GLint; width : GLsizei; height : GLsizei; border : GLint; format : GLenum; dtype : GLenum; data : System.Address)
        with Import, Convention => Stdcall, Address => glTexImage2D_C_Address;
    begin
        glTexImage2D_C(GLenum(target), GLint(level), GLint(internalFormat), GLsizei(width), GLsizei(height), GLint'(0), GLenum(format), GLenum(dtype), pixels);
    end;
end glTexImage2D;

--This seems to work... but here it is just in case.
procedure Set_OpenGL_Subprogram_Address(Addr : in out System.Address; Name : String) is
begin
    if Addr = System.Null_Address then
        Addr := SDL_GL_GetProcAddress(Value(New_String(Name)));
        if Addr = System.Null_Address then
            raise Could_Not_Load_OpenGL_Subprogram with Name;
        end if;
    end if;
end Set_OpenGL_Subprogram_Address;

Finally, the pixels I'm passing in is an address indicating an object of type:

type Uc_Array is array(Integer range <>) of aliased Interfaces.C.unsigned_char;

The stack is being corrupted on the call to glTexImage2D_C. I discovered this by using gdb:

enter image description here

Here you can see the parameters I'm passing as well; target 3553, level 0, internalformat 6408, width 63, height 63, format 6408, dtype 5121, non-zero pixels address. The subprogram address is being set to a non-zero value. But after the call to glTexImage2D_C, the value of $sp (the stack pointer) has increased by 16#24#.

I've tried adjusting the height and width I pass to glTexImage2D_C, both to 10 and both to 1000, just to see if giving it more (or less) buffer prevents stack corruption, but in every case, the stack pointer is different before and after the procedure call.

I'm hoping this is a simple matter of an incorrect datatype or something... Here's the prototype of glTexImage2D on the OpenGL side:

void glTexImage2D(  GLenum target,
    GLint level,
    GLint internalformat,
    GLsizei width,
    GLsizei height,
    GLint border,
    GLenum format,
    GLenum type,
    const void * data);

(As a final note, I do intend to clean up the awkward lazy loading tactic you see above, if I can ever get this to actually work. For now I'm leaving it this way so I can eliminate the chance of trying to call a function that hasn't been loaded yet, while I'm still trying to debug the call itself. The tactic of using a nested procedure declared inside a declare...begin...end block is working for other OpenGL functions.)

Bug in GNAT Get(FRom => SomeString, Item => SomeInteger, Last => Last)?

Get(TheFile, IntValue); works great with strings formatted like 16#12# to read hex values. Shouldn't Get from a string function the same way?

I tried this, but passing 16#12# only yields 16. Pure hex, eg F8 results in an exception

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure hex is
   IntValue  : Integer;
   Last : Positive;
begin
   Put("Enter a hexadecimal string: ");
   Get(HexString);

   -- Convert the hexadecimal string to an integer
   Get(From => HexString, Item => IntValue, Last => Last);

   Put ("The integer value is: ");
   Put (IntValue, Width => 0);
   New_Line;
end hex;

How to pass complex data types, like records between Ada and C via a DLL?

I am trying to get Ada code to compile to a DLL to be callable in C. So far I have managed to get this to work for simple types such as integers but i'm having difficulty with more complex types such as array's or records/structs.

Below is my Ada code for an record/struct. It is a dynamic library which i compile to a dll using the command "gprbuild -P ./math.gpr -p":

person.adb
with Interfaces.C; use Interfaces.C;

package body Person is

   function Set_Age_To_Five(P : Person_Record) return Person_Record is
      Result : Person_Record;
   begin
      Result := P;
      Result.Age := 5;
      return Result;
   end Set_Age_To_Five;

end Person;

person.ads

with Interfaces.C; use Interfaces.C;

package Person is

   type Person_Record is record
      Name    : String(1 .. 100);
      Age     : Interfaces.C.int;
      Address : String(1 .. 100);
   end record with Convention => C_Pass_By_Copy;

   function Set_Age_To_Five(P : Person_Record) return Person_Record;
   pragma Export (C, Set_Age_To_Five, "Set_Age_To_Five");

end Person;

math.gpr

library project Math is
    for Languages use ("Ada");
    for Library_Name use "Person";
    for Source_Dirs use ("src");
    for Object_Dir use "obj";
    for Library_Dir use "lib";
    for Library_Kind use "Dynamic";
end Math;

I then have a C header file math.h:

#ifndef MATH_H
#define MATH_H

#ifdef __cplusplus
extern "C"
#endif

typedef struct {
    char Name[101];
    int Age;
    char Address[101];
} Person_Record;

Person_Record Set_Age_To_Five(Person_Record P);

#ifdef __cplusplus

#endif

#endif /* MATH_H */

and finally my C code:

#include <stdio.h>
#include "math.h"

int main() {
    Person_Record p, q, r;

    // Initialize the person record
    snprintf(p.Name, sizeof(p.Name), "John");
    p.Age = 25;
    snprintf(p.Address, sizeof(p.Address), "123 Main St");

    // Call the Set_Age_To_Five function from the DLL
    q = Set_Age_To_Five(p);

    // Print the modified person record
    printf("Name: %s\n", q.Name);
    printf("Age: %d\n", q.Age);
    printf("Address: %s\n", q.Address);

    return 0;
}

This should when executed return

Name: John
Age: 5
Address: 123 Main St

Instead its returning:

Name: John
Age: 25
Address: 123 Main St

I've tried passing by variable, passing by reference. using convention C and convention pass by c in ada.

Errors trying to run gnattest

I'm trying to run gnattest on a Ada project file:

gnattest -P(projectname)

and I get the following errors:

object path not found for runtime native gnattest: initialization failed

I made sure the gnatpro-v20.2/bin directory was part of the path. I tried adding other gnat directories to the path. I tried running the command inside of GPS and from command line.

Getting the error "error: No index.toml file found in index", when trying to do "alr get gnat_native" and "alr get gprbuild" on Debian

I'm recieving the error error: No index.toml file found in index when I'm trying to use alr get gnat_native and alr get gprbuild on Debian. I made sure that Alire is installed, by using the 'alr' command I get 'alr 1.2.2' when I do the command.

I expected to download the Alire tools, and not to recieve a error when I do alr get gnat_native and `alr get gprbuild'. I made sure that Alire is installed, by using the 'alr' command I get 'alr 1.2.2' when I do the command.

Importing C function which accepts array of union

I'm working on an Ada language binding for a C library and stumbled upon a function which expects an array of union values. I tried to used Unchecked_Union aspect without defining discriminant record but it didn't work because Ada doesn't accept unconstrained element type in array.

In C, function and union are declared something like this:

union argument {
    int32_t i;
    uint32_t u;
    fixed_t f;        // custom 24.8 floating point type, defined as int32_t
    const char *s;    // string
    struct object *o; // custom object type
    uint32_t n;       // may be set as id from struct object (o->id) 
    struct array *a;  // custom array type
    int32_t h;        // file descriptor
};

.. foo(.., union argument *args);

I'm using GNAT toolchain and running gcc with -fdump-ada-spec produced type:

type argument (discr : unsigned := 0) is record
   case discr is
      when 0 =>
         i : aliased x86_64_linux_gnu_bits_stdint_intn_h.int32_t;
      when 1 =>
         u : aliased x86_64_linux_gnu_bits_stdint_uintn_h.uint32_t;
      when 2 =>
         f : aliased fixed_t;
      when 3 =>
         s : Interfaces.C.Strings.chars_ptr;
      when 4 =>
         o : access object;
      when 5 =>
         n : aliased x86_64_linux_gnu_bits_stdint_uintn_h.uint32_t;
      when 6 =>
         a : access array;
      when others =>
         h : aliased x86_64_linux_gnu_bits_stdint_intn_h.int32_t;
   end case;
end record
with Convention => C_Pass_By_Copy,
     Unchecked_Union => True;

I replaced unsigned discriminant with enum type and it works fine when I use it as a single value, or as an array of unchecked unions with same discriminant value, but I can't figure out the proper way of using different union components in Ada. I do have some ideas to workaround this though, but I'm not sure if they are correct or possible to implement in Ada.

Observations:

  • C function internally expects at most 20 items in an array
  • There is a companion function with similar signature that uses varargs instead of array of union type, varags are then converted to that union type

Option 1 Use varargs version and generate in Ada several overloaded functions with different count/type combinations. IIUC, this will require 20 * 8 function definitions, not fun at all.

Option 2 Write an import function with definite union type and then somehow cast with Unchecked_Conversion to/from values, i.e. array (Integer range 0..19) of argument(4), then convert elements of an array to different types.

Option 3 Take advantage of max array size and allocate (aliased) memory blob of 20 * 64 bytes (union size), write helper procedures which will read/write correct values at correct memory locations, and then pass this blob either as 'Access or 'Address to the C function. In this case function parameter would be access my_blob or just System.Address.

I'm personally leaning towards option 3, but it'll require a considerable amount of research/work/testing so I'm asking if there are better ways to do that.

P.S. I think it is a defect on Ada side as ARM B.3.3 Β§14/2 clearly states that "All objects of an unchecked union type have the same size", so it should be possible to create an array of unchecked unions without defining discriminant. But I understand that it was done to make code safer to use.

Ada types using "(<>)"

I am looking at some legacy Ada code.

type My_Test_Type is (<>);
type My_Table_Type is array(My_Test_Type) of Integer;

When I try to use this code in the GNAT community IDE, I get this error:

ads:9:26: error: identifier expected

This is the line it's pointing to:

type My_Test_Type is (<>);

When I build the code in the legacy IDE, it compiles and runs fine.

Any ideas what is going on here?

I've tried this only on my local PC running GNAT Studio Community 2021 (20210423) hosted on x86_64-w64-mingw32.

The legacy system is a cross compiler for the Power PC. It's old.

Ok, Here is more context.

I took the above lines an created a package which I am building and running in GNAT Studio community addition.

Here is the my_generic.ads

package My_Generic is
 generic
   type My_Test_Type is (<>);
   type My_Table_Type is array(My_Test_Type) of Integer;
   --
   My_Table : My_Table_Type;
   procedure InitMyTable(My_Table : My_Table_Type);   
end My_Generic;

Here is my_generic.adb

with GNAT.IO; use GNAT.IO;
package body My_Generic is
   procedure InitMyTable (My_Table : My_Table_Type) is
   begin
      Put_Line("Entered InitMyTable");
      for i in 1..1000 loop
         My_Table(i) := i + 1000;
      end loop;
      null;
   end InitMyTable;
end My_Generic;

Main is
--...
--...
   InitMyTable_i = new InitMyTable(My_Test_Type => range 1..10);
begin
--...
--...
   Put_Line ("Initializing My table (<>)");
   InitMyTable_i;

end Main;

when I build I get error: declaration expected on the line "InitMyTable_i = new InitMyTable(My_Test_Type => range 1..10);"

I basically have no idea what is going on here. I've tried many different ways to get things to work. Any of the docs I have found, including the ones suggested below, are not helpful.

Thanks

Ada: named access types and memory pools

I have read the following from wikibooks:

A pool access type handles accesses to objects which were created on some specific heap (or storage pool as it is called in Ada). A pointer of these types cannot point to a stack or library level (static) object or an object in a different storage pool. Therefore, conversion between pool access types is illegal. (Unchecked_Conversion may be used, but note that deallocation via an access object with a storage pool different from the one it was allocated with is erroneous.)

According the bold text, if the named access types belongs to the same memory pool then the conversion is legal?

I'm implementing a composite pattern, and I think I could improve the design if the composites return references to its concrete leaves and composites, avoiding the use of keyword "all" in the named access definition. I think I need memory pools to accomplish with it, but I think that it is an advanced feature and I haven't found enough documentation to be sure I can implement one by myself correctly.

I have been following the links shared in this post. Does anybody know other resources after ten years?

Compiling Ada library for Android (JNI)

I have written an application in Ada and I want to run it on Android (ARM devices). I have compiled a native standalone library for ARM (arm64-v8a) on a Raspberry Pi, containing the proper JNI. However, when I launch the application in Android it fails while loading the library (right on the System.loadLibrary call). Is there something theoretically wrong in proceeding this way, or should it work?

Before doing this experiment on android, I successfully loaded an Ada test library on Java using a x64 PC, so I don't think the problem is in the interface itself. I would have expected the library to be loaded without issues.

For the full code to see what I am trying to do, please, have a look at GuillermoHazebrouck/gnav on GitHub.

Why does elaboration require the programmers attention in Ada? [closed]

I stumbled upon an in depth explanation of elaboration, it's standardized ordering scheme, and the options available to the programmer for controlling it in unsuccessful cases.

http://www.cs.uni.edu/~mccormic/4740/documentation/elaboration

First, it's still unclear why elaboration needs to be addressed by the programmer at all. I've never dealt with it in any other language such as C, Pascal or C++ where the order of allocation and assignment variables, as well as code execution, are rarely of concern. Why isn't it automatically handled and what benefits does it offer to the developer?

Second, elaboration failures are often not detected statically, but at runtime only as a "program error" exception. I find it a bit disconcerting, considering it can suddenly occur in a number of scenarios, including changes in the runtime, the code base, the compiler or its version. It seems to belie Ada's core tenet of code safety and reliability.

Create a record with a private part

According to this post, I'v try to do a record with a private part. What I've done :

MyFile.ads :

package MyPackage is
  type T_MyType is tagged private;
private
  type T_MyType_Private_Part;
  type T_MyType_Private_Part_Access is access T_MyType_Pirvate_Part;
  type T_MyType is tagged record
    Toto : Boolean;
  end record
end MyPackage;

MyFile.adb :

package body MyPackage is
   type T_MyType_Private_Part is record
     Private_Toto : Boolean;
   end record
end MyPackage;

But when an other package do MyVar.Toto where MyVar is T_MyType I have the error :

no selector "Toto" for type "T_MyType" defined at MyFile.ads

How can I fix this ?

Getting unix command CAT to work on Windows

The issue of getting the equivalent command of the Unix command cat on Windows has been discussed for example here: What is the Windows equivalent of the Unix command cat?

I have looked at the project MinGW here: MinGW - Minimalist GNU for Windows Files

I have installed the file mingw-get-setup.exe and now I have a gui with which I can retrieve necessary Unix tools by downloading from the internet. But I do not know which of these tools has/have the cat command.

I would like to use the cat command to merge Ada specifications and bodies files so as to distribute the codes as just one .ada file on which other users can use the gnatchop command to retrieve the original files again.

If there are other better projects on Windows to obtain the cat command directly in a single Windows installation unlike the MinGW project in which tools have to be installed by downloading from the internet, I am interested.

Ada input format issue

I'm new to Ada and not sure how to fix this code. It appears it is about format issue,Β but don't know what is causing this. I am trying to read two files called a.txt and b.txt then compute the inverse of it. Sorry again am just stuck.

Here is the input files

A.txt

2 -2 4 -2 2 0 
1 0 4 -3 0 0
1 1 1 1 1 1 
1 0 0 -1 0 0
3 0 0 -3 0 2
1 0 0 0 -2 4

B.txt

13
18
51
82
32
12

here is my code

with Ada.Text_IO, Ada.Float_Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Float_Text_IO, Ada.Integer_Text_IO;

procedure Matrix_Inverse is

   type Matrix is array (1 .. 6, 1 .. 6) of Float;
   type Vector is array (1 .. 6) of Float;
   
   function Get_Matrix_From_File(Filename : String) return Matrix is
      A : Matrix := (others => (others => 0.0));
      File : File_Type;
      Line : String (1 .. 20);
      Last : Natural;
   begin
      Open (File, In_File, Filename);
      for I in A'Range(1) loop
         Get_Line (File, Line, Last);
         for J in A'Range(2) loop
            A (I, J) := Float'Value (Line (1 .. Last));
            Get (File, Line);
            Get_Line (File, Line, Last);
         end loop;
         A (I, 6) := Float'Value (Line (1 .. Last));
      end loop;
      Close (File);
      return A;
   end Get_Matrix_From_File;
   
   function Get_Vector_From_File(Filename : String) return Vector is
      B : Vector := (others => 0.0);
      File : File_Type;
   begin
      Open (File, In_File, Filename);
      for I in B'Range loop
         Get (File, B (I));
      end loop;
      Close (File);
      return B;
   end Get_Vector_From_File;
   
   procedure Print_Matrix(A : Matrix) is
   begin
      for I in A'Range(1) loop
         for J in A'Range(2) loop
            Put (A (I, J), 6, 2);
            Put (" ");
         end loop;
         New_Line;
      end loop;
   end Print_Matrix;
   
   function Inverse(A : Matrix) return Matrix is
      Inv : Matrix := (others => (others => 0.0));
      Identity : Matrix := (others => (others => 0.0));
   begin
      for I in Identity'Range(1) loop
         Identity (I, I) := 1.0;
      end loop;
      
      for I in A'Range(1) loop
         if A (I, I) = 0.0 then
            for J in I + 1 .. A'Range(1)'Last loop
               if A (J, I) /= 0.0 then
                  for K in A'Range(2) loop
                     A (I, K) := A (I, K) + A (J, K);
                     Identity (I, K) := Identity (I, K) + Identity (J, K);
                  end loop;
                  exit;
               end if;
            end loop;
         end if;
    for J in A'Range(1) loop
      if J /= I then
          declare
            Factor : constant Float := A (J, I) / A (I, I);
          begin
            for K in A'Range(2) loop
                A (J, K) := A (J, K) - Factor * A (I, K);
                Identity (J, K) := Identity (J, K) - Factor * Identity (I, K);
            end loop;
          end;
      end if;
    end loop;

    for I in A'Range(1) loop
      declare
          Diagonal : constant Float := A (I, I);
      begin
          for J in A'Range(2) loop
            Identity (I, J) := Identity (I, J) / Diagonal;
          end loop;
      end;
    end loop;

      return Identity;
    end Inverse;

  function Solve(A : Matrix; B : Vector) return Vector is
    Inv_A : Matrix := Inverse(A);
    Result : Vector := (others => 0.0);
  begin
    for I in Result'Range loop
        for J in Result'Range loop
          Result (I) := Result (I) + Inv_A (I, J) * B (J);
        end loop;
    end loop;
    return Result;
  end Solve;

  A : Matrix := Get_Matrix_From_File("a.txt");
  B : Vector := Get_Vector_From_File("b.txt");

  Solution : Vector := Solve(A, B);

  begin
    Put_Line("Solution:");
    for I in Solution'Range loop
        Put(Solution(I), 6, 2);
        Put(" ");
    end loop;
    New_Line;
end Matrix_Inverse;

Variable arglists in Ada

Why does not Ada support variable function/procedure argument lists? Is it hard to implement or does it somehow go against "we should keep things secure" philosophy of the language?

Varargs were over there at least as early as C and allow very handy things like printf, the likes of which can also be found in other languages like Java or C#. Another neat example is logging functions where it is usual to pass information from all kinds of data types, not only strings, in separate arguments.

And even if this is considered non-secure technique, Ada could still make it better than at least in C by e.g. throwing an exception if there is some mismatch between format string and the actually passed arguments.

Ada and C++ interface, avoid duplicated code [closed]

I'm working on a C++ application, Module_A, that has to use a diverse module, Module_B_Ada and Module_B_CPP depending on configuration.

Module_A + Module_B_Language will be compiled in different OS. I want to avoid duplicating Module_A to have a Module_A for Ada compilation and a Module_A for C++ compilation.

For now, the only thing that came to my mind has been to separate the code that uses the Ada module and exclude it from compilation when is compiled for C++ to avoid linking errors for unresolved symbols.

Another thing I'm thinking about is to comment the "extern" statement on the Module_A and define the Ada services to a void implementation when compiling for C++.

Have yoy ever faced a similar problem? How have you solved it?

Ada: Convert float to decimal

This post is linked to this one Ada 2005 access type. The goal is to use Ada decimal type to get similar results as to hand (and calculator) computations in which 6 decimal places have been used in each intermediate step.

As can be seen from the table below, the values obtained with the Ada code starts to differ from the hand calculation in the last digit when further iterations with the Euler method are taken.

One of the issues with the Ada code was with the line in the main code diff.adb: return 2 * Real(XY)*; It doesn't matter if I leave it as return 2 * X * Y as well.

The differential equation (O.D.E.) is being solved using the basic Euler method (which is an approximate method which is not that accurate). The D.E. is dy/dx = 2xy. The initial condition is at y0(x=x0=1) = 1. The analytical solution is y = e^((x^2)-1). The objective is to obtain y(x=1.5).

We start with the point (x0,y0) = (1,1). We use a step size h = 0.1 i.e. x is increased with each iteration in the Euler method to 1.1, 1.2, 1.3,..etc. and the corresponding value of y (the variable whose solution is being sought) is determined from the Euler algorithm which is:

y(n) = y(n-1) + h * f(x(n-1), y(n-1))

Here y(n-1) when we start the algorithm is y(0) = 1. Also x(n-1) is our starting x(0) = 1. The function f is the derivative function dy/dx given above as dy/dx = 2xy.

Briefly, h * f(x(n-1), y(n-1)) is the "horizontal distance between two successive x values" multiplied by the gradient. The gradient formula is dy/dx = delta y /delta x which gives delta y or (the change in y) as

delta y = delta x * dy/dx.

In the Euler formula h is the delta x and dy/dx is the gradient. So h * f(x(n-1), y(n-1)) gives delta y which is the change in the value of y i.e. delta y. This change in y is then added to the previous value of y. The Euler method is basically a first order Taylor approximation with a small change in x. A gradient line is drawn to the curve and the next value of the solution variable y is on this tangent line at the successive value of x i.e. xnew = xold + h where h is the step.

The table next shows the solution values for the variable y by the Euler method when calculated by hand (and calculator), by my Ada code and finally in the last column the exact solution.

x y (hand) Ada code y (exact)
1.1 1.200000 1.200000 1.233678
1.2 1.464000 1.464000 1.552707
1.3 1.815360 1.815360 1.993716
1.4 2.287354 2.287353 2.611696
1.5 2.927813 2.927811 3.490343

By hand and calculator for instance, y(x=1.1) i.e y(1) at x = x(1) is calculated as y(x=1.1) = y(0) + h * f(x=1,y=1) = 1 + 0.1 * (2 * 1* 1) = 1.200000 to 6 d.p.

y(2) is calculated at x = x(2) as y(x=1.2) = y(1) + h * f(x=1.1,y=1.200000) = 1.200000 + 0.1 * (2 * 1.1* 1.200000) = 1.464000 to 6 d.p.

y(3) is calculated at x = x(3) as y(x=1.3) = y(2) + h * f(x=1.2,y=1.464000) = 1.464000 + 0.1 * (2 * 1.2* 1.464000) = 1.815360 to 6 d.p.

y(4) is calculated at x = x(4) as y(x=1.4) = y(3) + h * f(x=1.3,y=1.815360) = 1.815360 + 0.1 * (2 * 1.3* 1.815360) = 2.287354 to 6 d.p.

y(5) is calculated at x = x(5) as y(x=1.5) = y(4) + h * f(x=1.4,y=2.287354) = 2.287354 + 0.1 * (2 * 1.4* 2.287354) = 2.927813 to 6 d.p.

Now I want to modify the codes so that they work with a fixed number of decimal places which is 6 here after the decimal place.

The main code is diff.adb:

with Ada.Text_IO;
with Euler;
procedure Diff is

  type Real is delta 0.000001 digits 9;
  type Vector is array(Integer range <>) of Real;
  type Ptr is access function (X: Real; Y: Real) return Real;
   
  package Real_IO is new Ada.Text_IO.Decimal_IO(Num => Real); 
  use Real_IO; 

  procedure Solve is new Euler(Decimal_Type => Real, Vector_Type => Vector, Function_Ptr => Ptr);

  function Maths_Func(X: Real; Y: Real) return Real is
  begin
    return 2 * Real(X*Y);
  end Maths_Func;

  
  Answer: Vector(1..6);

begin
  Solve(F => Maths_Func'Access, Initial_Value => 1.0, Increment => 0.1, Result => Answer);
  for N in Answer'Range loop
    Put(1.0 + 0.1 * Real(N-1), Exp => 0);
    Put( Answer(N), Exp => 0);
    Ada.Text_IO.New_Line;
  end loop;
end Diff;

Then comes euler.ads:

generic
  type Decimal_Type is delta <> digits <>;
  type Vector_Type is array(Integer range <>) of Decimal_Type;
  type Function_Ptr is access function (X: Decimal_Type; Y: Decimal_Type) return Decimal_Type;
procedure Euler(
  F: in Function_Ptr; Initial_Value, Increment: in Decimal_Type; Result: out Vector_Type);

and the package body euler.adb

procedure Euler
  (F : in Function_Ptr; Initial_Value, Increment : in Decimal_Type; Result : out Vector_Type)
is
   Step : constant Decimal_Type := Increment;
   Current_X : Decimal_Type := 1.0;

begin
   Result (Result'First) := Initial_Value;
   for N in Result'First + 1 .. Result'Last loop
      Result (N) := Result (N - 1) + Step * F(Current_X, Result (N - 1));
      Current_X := Current_X + Step;
   end loop;
end Euler;

On compilation, I get the messages pointing to diff.adb:

type cannot be determined from context

explicit conversion to result type required

for the line return 2.0 times X times Y;

Perhaps the 2.0 is causing the trouble here. How to convert this Float number to Decimal?

I believe that further down in diff.adb, I will get the same issue with the line:

Solve(F => Maths_Func'Access, Initial_Value => 1.0, Increment => 0.1, Result => Answer);

for it contains Floating point numbers as well.

The compilation was done on Windows with the 32-bit GNAT community edition of year 2011. Why 2011? This is because I like the IDE better for that year rather than the pale ones which come in the recent years.

The revised codes based on trashgod codes which work are given next:

The main file diff.adb

with Ada.Numerics.Generic_Elementary_Functions; use Ada.Numerics;
with Ada.Text_IO;                               use Ada.Text_IO;
with Euler;

procedure Diff is

   type Real is digits 7;
   type Vector is array (Positive range <>) of Real;
   type Ptr is access function (X : Real; Y : Real) return Real;
   type Round_Ptr is access function (V : Real) return Real;

   procedure Solve is new Euler (Float_Type => Real, Vector => Vector, Function_Ptr => Ptr, Function_Round_Ptr => Round_Ptr);
   package Real_Functions is new Generic_Elementary_Functions (Real);
   use Real_Functions;
   package Real_IO is new Ada.Text_IO.Float_IO (Real);
   use Real_IO;

   function DFDX (X, Y : Real) return Real is (2.0 * X * Y);
   function F (X : Real) return Real is (Exp (X**2.0 - 1.0));
   function Round (V : in Real) return Real is (Real'Rounding (1.0E6 * V) / 1.0E6);

   XI      : constant Real := 1.0;
   YI      : constant Real := 1.0;
   Step    : constant Real := 0.1;
   Result  : Vector (Positive'First .. 6); --11 if step = 0.05
   X_Value : Real;

begin
   Solve (DFDX'Access, Round'Access, XI, YI, Step, Result);
   Put_line("        x      calc     exact     delta");
   for N in Result'Range loop
      X_Value := 1.0 + Step * Real (N - 1);
      Put (X_Value, Exp => 0);
      Put (" ");
      Put (Result (N), Exp => 0);
      Put (" ");
      Put (F (X_Value), Exp => 0);
      Put (" ");
      Put (Result (N) - F (X_Value), Exp => 0);
      Ada.Text_IO.New_Line;
   end loop;
end Diff;

The file euler.ads

generic
   type Float_Type is digits <>;
   type Vector is array (Positive range <>) of Float_Type;
   type Function_Ptr is access function (X, Y : Float_Type) return Float_Type;
   type Function_Round_Ptr is access function (V : Float_Type) return Float_Type;
procedure Euler
  (DFDX : in Function_Ptr; Round : Function_Round_Ptr; XI, YI, Step : in Float_Type; Result : out Vector);

The file euler.adb

procedure Euler
  (DFDX : in Function_Ptr; Round : Function_Round_Ptr; XI, YI, Step : in Float_Type; Result : out Vector)
is
   H : constant Float_Type := Step;
   X : Float_Type          := XI;
begin
   Result (Result'First) := YI;
   for N in Result'First + 1 .. Result'Last loop
       Result (N) :=  Round(Result (N - 1)) + Round(H * DFDX (X, Result (N - 1)));
       X          := X + Step;
   end loop;
end Euler;

giving the output with **step h = 0.1 **

x calc (Ada) exact delta
1.1 1.200000 1.233678 1.233678
1.2 1.464000 1.552707 -0.033678
1.3 1.815360 1.993716 -0.088707
1.4 2.287354 2.611696 -0.178356
1.5 2.927813 3.490343 -0.562530

The calc (Ada) results agree with hand (and calculator) computations.

❌