March 6, 2026

Adventures with memcpy and the RP2040 - Introduction

Here is the original email (with minor edits) that I received from Julian on March 4, 2026. He has clearly done his homework and has stumbled across an interesting bit of programming.
I am trying to reverse engineer an RP2040 program, and I notice that, in the `__wrap___aeabi_memcpy` function, the processor loads 0x434d into R3 and then branch-exchanges using R3. I believe the source code for this function is in the Pico SDK, in the file pico-sdk/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S, at lines 92-97. I've been trying to figure out exactly what it is doing here, and in my research, I stumbled across a post on your website. I was wondering if you might be knowledgeable enough to help me figure it what is going on here.

I believe that the wrapper function defined in that source code is meant to call the bootrom version of the `memcpy` function. As per Table 165 in Section 2.8.3.1.2 of the RP2040 datasheet (20 February 2025 release), 0x434d is the lookup code for the `_memcpy` function ('M', 'C'), in little-endian. But this is where I am confused. If this is just the function's lookup code, and not the function's actual address in memory, why would the program be using 0x434d as the target value for a branch-exchange here? Is this a coincidence, where the function's lookup code happens to be identical (barring the instruction set selection bit) to the function's address? What is going on here? Am I misunderstanding something?

It took me a while to get up to speed, but he is correct in all he says and it is not at all trivial or obvious what is going on here.


Have any comments? Questions? Drop me a line!

Tom's software pages / tom@mmto.org