Search code examples
nullarmadamemory-addressarmv6

Reading from Address 0x0 in Ada


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:

  • Ravenscar Small-footprint Runtime ported to Arm Cortex M1
  • Running on softcore processor instantiated inside a Microsemi RTG4 FPGA

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?


Solution

  • 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.