I don't quite understand, how the following typedef is parsed by a compiler to call code at a specific address. I guess I understand that a function is just a pointer and we're typedefing such a pointer. But what actually happens at compile and run time and where will the arguments get placed?

From the SAML10 Family datasheet(https://www.microchip.com/wwwproducts/en/ATSAML10E15A)

The CRYA APIs which are located in a dedicated Boot ROM area are only accessible from the user application after the Boot ROM has completed. This area is an execute-only area, meaning the CPU cannot do any loads, but can call the APIs.

/* Type definition for CRYA AES functions. */
typedef void (*crya_aes_encrypt_t) (const uint8_t *keys, uint32_t key_len, const uint8_t *src, uint8_t *dst);
#define secure_crya_aes_encrypt ((crya_aes_encrypt_t ) (0x02001904 | 0x1))

How function calls work depends on the calling convention. Most of the time, there will be a call stack in memory which can be used to pass function arguments etc. around. A calling convention will typically work like this:

  • save dirty registers to the stack
  • push function arguments to the stack
  • call the function
    • push the return address (next program counter) to the stack
    • jump to the function address

Calling conventions may allow some arguments to be passed in registers, and may provide for a different order of the items on the stack.

The called function can then access the arguments on the stack, and use the stack to manage its own temporary data. When returning, the function will:

  • clean up its own stack usage
  • push the return value onto the stack
  • jump to the return address that the caller wrote to the stack

So a function call only needs to manipulate memory of the stack, not of the function itself.

Many CPUs have security features that prevent the memory from being used freely. For example, the stack area might be writeable and readable but not executable: you can't call a function that is located on the stack. And the memory pages that contain executable code are marked as non-writeable. Here, the manual tells you that the memory of this function is also unreadable: you cannot load data from these pages, and the CPU only lets you jump to addresses in this protected region.

A compiler can create the necessary machine code for a function call without knowing its target. It just needs to know the function signature (number and types of arguments) and the calling convention. That is why functions must be declared first in C. The typedef describes this information.

The machine code can later be rewritten on the fly to point to the correct address of the function, this is called “linking”. Here, the target of the function call is known in advance, so the macro can provide the address of the function body's machine code.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.