I am running on a bare-board runtime, and reading data from address zero is a valid use case in my software. However, the runtime treats address 0x0 as null
, and throws an exception in the following code when compiled with -O2
. The code behaves as expected when compiled with -O1
:
declare
use System.Storage_Elements;
type Byte_Array is array (Natural range 0 .. 3) of Interfaces.Unsigned_8;
bytes : constant Byte_Array with Import, Convention => Ada, Address => To_Address(Integer_Address(16#00000000#));
begin
-- Copy bytes to some other byte array in memory:
other_bytes := bytes; -- Throws exception
end;
Is there any way around this problem?
Details on my platform:
Details on the failure:
The previous code dies in my runtime in the memcpy
function implemented by s-memcop.adb
. The code is copied below, with a comment reporting the line which fails. I am unsure of the actual exception that gets thrown. All I can see is the the last chance handler gets called with the information s-memcop.adb:52
, which is commented below.
40 function memcpy
41 (Dest : Address; Src : Address; N : size_t) return Address
42 is
43 D : IA := To_IA (Dest);
44 S : IA := To_IA (Src);
45 C : size_t := N;
46
47 begin
48 -- Try to copy per word, if alignment constraints are respected
49
50 if ((D or S) and (Word'Alignment - 1)) = 0 then
51 while C >= Word_Unit loop
52 To_Word_Ptr (D).all := To_Word_Ptr (S).all; -- Last_Chance_Handler Called here :(
53 D := D + Word_Unit;
54 S := S + Word_Unit;
55 C := C - Word_Unit;
56 end loop;
57 end if;
58
59 -- Copy the remaining byte per byte
60
61 while C > 0 loop
62 To_Byte_Ptr (D).all := To_Byte_Ptr (S).all;
63 D := D + Byte_Unit;
64 S := S + Byte_Unit;
65 C := C - Byte_Unit;
66 end loop;
67
68 return Dest;
69 end memcpy;
Is there a way to see the actual exception being thrown?
I got in contact with AdaCore and received a solution to this problem:
If you compile at -O2 or above, then you also need to pass to the compiler the switch -fno-delete-null-pointer-checks because -fdelete-null-pointer-checks is automatically enabled at -O2 for the ARM architecture.
According to the docs the -fdelete-null-pointer-checks
flag:
Assume that programs cannot safely dereference null pointers, and that no code or data element resides at address zero.
Since this is NOT true of my application, and I need to access data at address zero, I needed to disable this switch by passing the compiler the -fno-delete-null-pointer-checks
option.
Note: I had issues when the optimization flags of my code and the runtime were not consistent. In this case, compiling my code AND the runtime with the -O2
and -fno-delete-null-pointer-checks
options allowed me to freely read/write address 0x0.