I'm attempting to pass a structure from (x86) assembler to Ada on the stack. I've been able to successfully use this pattern in C to accept to wrap a large number of arguments passed from assembly inside a struct and I'm wondering if this will work in a similar way in Ada.
Here is a (contrived, minimal) example:
When I do this, debugging the callee shows that the passed record contains uninitialised data. It appears that Ada is interpreting the C calling convention differently despite the export directive.
The RM contains information about passing structs from Ada to C, saying that it will automatically pass a record as a pointer type, but the inverse does not appear to be true. If you accept a single access
type it will simply be filled with the first value on the stack, as one would expect from cdecl.
( Please excuse any minor errors, this isn't my actual code. )
#####################################################################
# Caller
#
# This pushes the values onto the stack and calls the Ada function
#####################################################################
.global __example_function
.type __example_function, @function
__example_function:
push $1
push $2
push $3
push $4
call accepts_struct
ret
----------------------------------------------------------------------------
-- Accepts_Struct
--
-- Purpose:
-- Attempts to accept arguments pass on the stack as a struct.
----------------------------------------------------------------------------
procedure Accepts_Struct (
Struct : Struct_Passed_On_Stack
)
with Export,
Convention => C,
External_Name => "accepts_struct";
----------------------------------------------------------------------------
-- Ideally the four variables passed on the stack would be accepted as
-- the values of this struct.
----------------------------------------------------------------------------
type Struct_Passed_On_Stack is
record
A : Unsigned_32;
B : Unsigned_32;
C : Unsigned_32;
D : Unsigned_32;
end record
with Convention => C;
On the other hand, this works just fine:
procedure Accepts_Struct (
A : Unsigned_32;
B : Unsigned_32;
C : Unsigned_32;
D : Unsigned_32
)
with Export,
Convention => C,
External_Name => "accepts_struct";
That's not a big deal in this minimal case, but if I'm passing 16 or more variables it gets a bit onerous. If you're wondering why I'm doing this, it's an exception handler where the processor automatically passes variables onto the stack to show register states.
Any help here would be greatly appreciated.