# Memory mapped record object issue

**URL:** https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106
**Category:** General
**Created:** [January 11, 2026, 7:05pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106 "2026-01-11T19:05:16Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![sidisyom](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/5fc32e/32.png) [@sidisyom](https://forum.ada-lang.io/u/sidisyom)
#### Post date: [January 11, 2026, 7:05pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/1 "2026-01-11T19:05:16Z")

</div>

Hi,

I am using a memory-mapped record object and have come across an issue around the memory addresses assigned to an object of that record.

Suppose the following record declaration and representation clause:

```ada
type ADC_DR_Register is
  record
     DATA : Hal.UInt16;
     Reserved : Hal.Uint16;
  end record
 with 
   Volatile_Full_Access,
   Bit_Order => System.Low_Order_First,
   Object_Size => 32;
 
for ADC_DR_Register use
  record
     DATA at 0 range 0 .. 15;
     Reserved at 0 range 16 .. 31;
  end record;

```

which is then memory-mapped to some peripheral address.

An object of that record is then declared (as the composite part of a different record) and subsequently the addresses assigned both to the record object itself _and_ the first item declared in the record are printed:

```ada
Addr1 : System.Address := ADC_Registers.ADC_Periph.ADC_DR'Address with Volatile;
Addr2 : System.Address := ADC_Registers.ADC_Periph.ADC_DR.DATA'Address with Volatile;

```

Printing these in gdb yields:

```ada
(gdb) p Addr1 
$1 = (system.address) 0x4001204c
(gdb) p Addr2
$2 = (system.address) 0x20004940

```

and contrary to what I intuitively believed would be the case, these addresses are different. This is flashed into an stm32f429 board (which is a cortex-M\*-based board) so it looks like the object-based address `Addr1` is correctly overlaid within the peripheral address space whereas the component-based one `Addr2` seems to be in SRAM like any other declared non-memory-mapped object would be. Intuitively, it feels as if there’s some kind of handle or proxy in the middle which is indirectly delegating to one memory address or the other but I’m not too sure? 🤔

Not massively important, but for context, this is implementing a manual (i.e. non-ADL) ADC/DMA flow in the aforementioned board and it caused some interesting issues when running the code. Initially, I specified the `DATA` component as the value for the peripheral address in my DMA configuration as in:

```ada
-- Set peripheral address (the data register of the ADC module)
DMA_SxCR.DMA2_Controller.DMA_SPAR := Address_To_Integer (ADC_Registers.ADC_Periph.ADC_DR.DATA'Address);

```

Which, as demonstrated above, is the wrong address and had a somewhat interesting effect as what happens is that the DMA controller is hitting the SRAM address and not the peripheral one which means that the `DATA` register is never read which in turn means that the second channel conversion of the first ever scan causes an overrun (and the whole ADC/DMA flow stops and has to be reset).

After several days of intense debugging (that can be hard to spot!) and carefully going through the configuration on both sides again and again (I was definitely sure I’m missing something on that..) I thought of checking the addresses and finally spotted what was going on. Specifying `Addr1` as the peripheral address results in the DMA controller reading from the correct address and the conversions/memory stores work just fine with no overrun errors.

I haven’t tried using a single scalar object for the representation of that register yet (which I assume _should_ work?) but was keen to initially understand why this compiler behaviour occurs. Any pointers or references where this is detailed would be greatly appreciated.

(using a `gnat_arm_elf = "=15.2.1"` cross compiler)

Thanks!

---

<div class="post-metadata">

### Author: ![OneWingedShark](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/onewingedshark/32/305_2.png) [@OneWingedShark](https://forum.ada-lang.io/u/OneWingedShark)
#### Post date: [January 11, 2026, 9:29pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/2 "2026-01-11T21:29:38Z")

</div>

> [@sidisyom](#):
>
> Printing these in gdb yields:
> 
> ```ada
> (gdb) p Addr1 
> $1 = (system.address) 0x4001204c
> (gdb) p Addr2
> $2 = (system.address) 0x20004940
> 
> ```
> 
> and contrary to what I intuitively believed would be the case, these addresses are different.

Try adding `For ADC_DR_Register'Alignment use 0;`, as IIRC, this is an alignment-issue, and (again, IIRC) the `0` is the special case of _“no alignment restrictions”_.

---

<div class="post-metadata">

### Author: ![sttaft](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/sttaft/32/12_2.png) [@sttaft](https://forum.ada-lang.io/u/sttaft)
#### Post date: [January 12, 2026, 7:21pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/3 "2026-01-12T19:21:59Z")

</div>

This result looks very strange. Can you include the code you used to memory map the object to some peripheral address? The addresses are not just a little different. They are wildly different. That really makes no sense. This isn’t just an alignment issue…

---

<div class="post-metadata">

### Author: ![sidisyom](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/5fc32e/32.png) [@sidisyom](https://forum.ada-lang.io/u/sidisyom)
#### Post date: [January 12, 2026, 9:25pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/4 "2026-01-12T21:25:41Z")

</div>

Sure, good point, I may have messed something there!

Not sure if you are familiar with the registers structure for the ADC unit for this specific MCU (let me know and I can share a few more details on that) but there’s a number of registers that can be memory-mapped and in my case I am only mapping a subset of these by carefully setting the correct offsets in the representation clause.

So, the declaration of the enclosing record and the representation clauses look like the following:

 ![Screenshot from 2026-01-12 20-57-02](https://forum.ada-lang.io/uploads/default/original/1X/4a5bd807fc291f1a5ecdd681d48cc7c47122d4ce.png)

As you can see there are some gaps in the mapping which the `[-gnatw.h]` flag is correctly reporting. Most importantly though the `ADC_DR` offset should be the right one based on what’s mentioned in the RM (which also aligns with the printed value of `Addr1` mentioned above):

 ![Screenshot from 2026-01-12 21-14-38](https://forum.ada-lang.io/uploads/default/original/1X/d8794cf528785b7eb2406e176cee5710c36af9f9.png)

The `ADC1_Base_Address` is declared as:

![Screenshot from 2026-01-12 21-17-54](https://forum.ada-lang.io/uploads/default/original/1X/890b30e704bb1c9e7bba3407cd23453e976bcaa6.png)

which I believe is the correct address for the ADC1 unit.

So, in my current understanding (which could be flawed/limited), the addresses for the entire record object itself and the first component of that object should match? 🤔

Thank you.

---

<div class="post-metadata">

### Author: ![sidisyom](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/5fc32e/32.png) [@sidisyom](https://forum.ada-lang.io/u/sidisyom)
#### Post date: [January 12, 2026, 9:27pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/5 "2026-01-12T21:27:34Z")

</div>

Specifying that gives the following error:  
 ![Screenshot from 2026-01-12 21-01-10](https://forum.ada-lang.io/uploads/default/original/1X/65f336c5b4ab9adbd635293c79ae4aacf6e5087e.png)

So something in the word accesses that the compiler doesn’t like.. 🤔

Thank you.

---

<div class="post-metadata">

### Author: ![sttaft](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/sttaft/32/12_2.png) [@sttaft](https://forum.ada-lang.io/u/sttaft)
#### Post date: [January 12, 2026, 9:44pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/6 "2026-01-12T21:44:24Z")

</div>

> [@sidisyom](#):
>
> So, in my current understanding (which could be flawed/limited), the addresses for the entire record object itself and the first component of that object should match? 🤔

I agree. That is why the result you are getting looks so weird.

It would be ideal if you could provide a self-contained compilable and linkable piece of code including the definitions of Addr1 and Addr2. That would make it easier for someone else to try to duplicate the problem you are seeing.

---

<div class="post-metadata">

### Author: ![sidisyom](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/5fc32e/32.png) [@sidisyom](https://forum.ada-lang.io/u/sidisyom)
#### Post date: [January 12, 2026, 10:07pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/7 "2026-01-12T22:07:03Z")

</div>

Ok great, let me see if I can push that on some Github repo somehow..! Thank you.

---

<div class="post-metadata">

### Author: ![OneWingedShark](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/onewingedshark/32/305_2.png) [@OneWingedShark](https://forum.ada-lang.io/u/OneWingedShark)
#### Post date: [January 12, 2026, 11:07pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/8 "2026-01-12T23:07:34Z")

</div>

> [@sidisyom](#):
>
> So, the declaration of the enclosing record and the representation clauses look like the following:
> 
> ![Screenshot from 2026-01-12 20-57-02](https://forum.ada-lang.io/uploads/default/original/1X/4a5bd807fc291f1a5ecdd681d48cc7c47122d4ce.png)

I find it’s a good idea to align your representation clause:

```ada
for ADC_Peripheral use record
   ADC_SR at 16#00# range 0 .. 31;
   ADC_CR1 at 16#04# range 0 .. 31;
   ADC_CR2 at 16#08# range 0 .. 31;
   ADC_SMPR2 at 16#10# range 0 .. 31;
   ADC_SOR1 at 16#2C# range 0 .. 31;
   ADC_SQR2 at 16#30# range 0 .. 31;
   ADC_SQR3 at 16#34# range 0 .. 31;
   ADC_DR at 16#4C# range 0 .. 31;
end record;

ADC_periph : aliased ADC_Peripheral 
   with Import, Address => System'To_Address (ADC1_Base_Address),

```

Another thing you can try (though 256-bits may be too big; IIRC, GNAT has a 128-bit size-limit) is defining everything by bit-position, so `XXX at 0 range 32..63;`

---

<div class="post-metadata">

### Author: ![sidisyom](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/5fc32e/32.png) [@sidisyom](https://forum.ada-lang.io/u/sidisyom)
#### Post date: [January 12, 2026, 11:22pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/9 "2026-01-12T23:22:03Z")

</div>

In case anyone wants to give that a try please clone [this](https://github.com/sidisyom/ada-sandbox) repo. If you place a copy of the ADL at the same level as the project file (or just give the absolute path if you already have that somewhere else) you should be able to compile and link in alire and get an elf file in the `bin` dir.

The main procedure is [this](https://github.com/sidisyom/ada-sandbox/blob/134f32a727781f5838bf37aca605315cc0ef8c13/src/dma/adc_dma_data_transfer.adb#L23) one and the two addresses in question are [here](https://github.com/sidisyom/ada-sandbox/blob/134f32a727781f5838bf37aca605315cc0ef8c13/src/dma/adc_dma_data_transfer.adb#L121-L122).

Apologies for this slightly chaotic repo but this is some _really_ ad-hoc stuff I use as a sandbox area so please ignore anything else except the main file mentioned above (sorry, haven’t got too much time to properly separate these out now..)

The code should be fairly straightforward to follow but do let me know if something doesn’t make sense.

Thanks!

(Obviously, no crate-level material..🙂 )

---

<div class="post-metadata">

### Author: ![SweetAda](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/7993a0/32.png) [@SweetAda](https://forum.ada-lang.io/u/SweetAda)
#### Post date: [January 14, 2026, 9:11pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/10 "2026-01-14T21:11:22Z")

</div>

Your code is fine. Update your compiler.

That being said, some random annotations (that you can throw away if you don’t like them):

- ADC\_SR\_Register.Reserved field is 26 bits wide, not 25. It is even more dangerous that your compiler does not flag this
- Avoid, whenever possible, to define Volatile\_Full\_Access for a type, unless you pass a reference for these objects
- you may want to insert Reserved fields also in the final layout to highlight unused space

---

<div class="post-metadata">

### Author: ![sidisyom](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/5fc32e/32.png) [@sidisyom](https://forum.ada-lang.io/u/sidisyom)
#### Post date: [January 14, 2026, 11:25pm UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/11 "2026-01-14T23:25:25Z")

</div>

> [@SweetAda](#):
>
> Update your compiler

Hmm, I seem to be on the latest version according to `alr toolchain --select`

> [@SweetAda](#):
>
> ADC\_SR\_Register.Reserved field is 26 bits wide, not 25

Ah! good spot, thank you..based on my understanding it’s the representation clause that’s the final arbiter for this and things like `Object_Size` but could be wrong

> [@SweetAda](#):
>
> Avoid, whenever possible, to define Volatile\_Full\_Access for a type, unless you pass a reference for these objects

So maybe you’re already aware of this but this is a tricky one on this mcu. By design (feature/bug?) it only deals with 32-bit accesses on the APB buses which the peripherals are attached to. Any other access is silently converted to a 32-bit access by cloning the byte or half-word across the full 32 range:

 ![Screenshot from 2026-01-14 23-00-21](https://forum.ada-lang.io/uploads/default/original/1X/bc0e602cba2bcee794704ecfd3685c9caa541fd2.png)

This can cause some really bizarre behaviour when the compiler issues byte or half-word accesses cause the end effect is basically to override the contents of a register. I’ve had this [issue](https://forum.ada-lang.io/t/weird-behaviour-in-record-mapping/1825/2) in the past and it was somewhat hard to diagnose.  
Was really keen to understand a bit more about using that when passing references of objects. Would you mind elaborating on that for a bit more, please?

> [@SweetAda](#):
>
> you may want to insert Reserved fields also in the final layout to highlight unused space

Makes total sense, I guess beneficial for documentation purposes too.

Thanks very much for looking into it, much appreciated. 🙏

---

<div class="post-metadata">

### Author: ![OneWingedShark](https://forum.ada-lang.io/user_avatar/forum.ada-lang.io/onewingedshark/32/305_2.png) [@OneWingedShark](https://forum.ada-lang.io/u/OneWingedShark)
#### Post date: [January 15, 2026, 1:06am UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/12 "2026-01-15T01:06:03Z")

</div>

> [@SweetAda](#):
>
> you may want to insert Reserved fields also in the final layout to highlight unused space

> [@sidisyom](#):
>
> Makes total sense, I guess beneficial for documentation purposes too.

There’s an argument for _ **not** _ having a `Reserved` field (or fields), and that is that if you don’t give it a name, you can’t manipulate it — and so `(others => <>)` can’t incorrectly stomp on the data — but if you _must_ give the reserved areas a field, be sure that you have the proper model, which are `null record` types of the appropriate sizes.

---

<div class="post-metadata">

### Author: ![Micronian2](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/m/e56c9b/32.png) [@Micronian2](https://forum.ada-lang.io/u/Micronian2)
#### Post date: [January 15, 2026, 6:59am UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/13 "2026-01-15T06:59:33Z")

</div>

I recall reading somewhere that since memory is frequently reused as objects are allocated/deallocated (from either heap or stack), a method to help avoid leaking sensitive data in the gaps/padding within data structures is to ensure every bit is covered by a field and assigned a value. The example given was to avoid sensitive kernel space data from leaking into user space when passing data from the former to the latter. The literature also mentioned thar simply having an allocator zero out the memory allocated to an object prior to populating the fields was insufficient since memory operations to update each field could still lead to the gaps getting populated with data.

---

<div class="post-metadata">

### Author: ![SweetAda](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/7993a0/32.png) [@SweetAda](https://forum.ada-lang.io/u/SweetAda)
#### Post date: [January 15, 2026, 10:12am UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/14 "2026-01-15T10:12:25Z")

</div>

Often when you write a register, you have to write all the fields – including reserved ones – with a defined value. Of course with proper size.

I was not able to find another way, but to name them “reserved” and give them a default value. You may raise an objection in that, in this case, my annotation is for whole registers in a peripheral layout, but mine was just a general approach. And explicitly touch a reserved field should ring a bell in the first instance.

---

<div class="post-metadata">

### Author: ![SweetAda](https://forum.ada-lang.io/letter_avatar_proxy/v4/letter/s/7993a0/32.png) [@SweetAda](https://forum.ada-lang.io/u/SweetAda)
#### Post date: [January 15, 2026, 10:52am UTC](https://forum.ada-lang.io/t/memory-mapped-record-object-issue/4106/15 "2026-01-15T10:52:20Z")

</div>

> [@sidisyom](#):
>
> Hmm, I seem to be on the latest version according to `alr toolchain --select`

Your code does compile without warnings with stock FSF 14.2.

> [@sidisyom](#):
>
> Would you mind elaborating on that for a bit more, please?

Indeed I specified a _ **type** _. Objects declared VFA are ok. Types should be VFA when access is involved, and they have to match across function call. But do not take it as a nazi rule, and it is more suited for whole registers that can fit in a CPU register.

> [@sidisyom](#):
>
> Thanks very much for looking into it, much appreciated. 🙏

Yay sir.
