How arguments passed into с function?

How arguments passed into с function?

The question is on the knowledge of such a thing as?Procedure Call Standard. It differs for different architectures. I will consider this standard for the?Arm?architecture.

Arguments pass into function

According to paragraph 6?of Procedure Call Standard for the Arm Architecture?registers?R0-R3?are used to pass arguments to the function, if the number of arguments exceeds the number of free registers, then the arguments are passed through the stack.

Let's take a look at an example:?

No alt text provided for this image

Let's call this function and look at the contents of the registers?R0-R3:

No alt text provided for this image
No alt text provided for this image

As we can see according?Procedure Call Standard for the Arm Architecture?all 4 arguments stores in?R0-R3?registers?accordingly.

Let`s see now what happens if we add one more argument:

No alt text provided for this image
No alt text provided for this image

The arguments?a,?b,?c,?d?stores in?R0-R3?as in previous function but?e?stores in the stack.

Everything seems to look clear and logical, but nevertheless there are several features here that we will now consider.

Passing of uint8_t, uint16_t arguments

Since the registers?R0-R3?have a size of 32 bits, they perfectly store any arguments having a size equal to or less than 32 bits.

Moreover, arguments with a size less than 32 bits (uint8_t,?int8_t,?uint16_t,?int16_t) occupy the entire register and are not packed into it, even if two or more arguments can be placed in the one register:

No alt text provided for this image
No alt text provided for this image

As you can see, 8-bit arguments occupy each their own 32-bit register.

Passing of uint64_t arguments

  • uint64_t?type must be aligned to the boundary of 8 bytes in memory
  • The 64 bits arguments may occupy only:?R0 + R1?or?R2 + R3?registers

No alt text provided for this image
No alt text provided for this image

Due to the fact that the 64 bits arguments can occupy only pairs of registers?R0 + R1?or?R2 + R3, when passing a function of mixed arguments (uint64_t?and smaller types), some registers may not be used to pass arguments.

For example in the function:

No alt text provided for this image

The register?R1?remains unused, but all 4 registers are spent, although only two parameters are passed and they should occupy only three registers in size:

No alt text provided for this image

If there was a third argument, for example, uint32_t, it would already be located on the stack.

No alt text provided for this image
No alt text provided for this image

Therefore, when creating a prototype of a function, especially if there are?uint64_t?arguments, you need to take a closer look at the issue of the location of the arguments, because the correct location will help to win a little in performance due to the location of all arguments in the processor registers, and not on the stack. So for example, if in the previous example you swap the arguments?b?and?c, then all the arguments will fit in the registers?R0-R3:

No alt text provided for this image
No alt text provided for this image

Alignment when passing arguments through the stack

When using the stack to pass arguments to a function, all arguments (except?uint64_t) in the stack are aligned along the 4-byte boundary:

No alt text provided for this image
No alt text provided for this image

64-bit arguments are aligned along the 8-byte boundary:

No alt text provided for this image
No alt text provided for this image

Passing a structure as an argument

When passing a structure as an argument to a function, a simple rule applies:?if the size of the structure is less than 16 bytes (the size of 4 registers?R0-R3), then the structure (its fields) are stored in processor registers, if the size is greater than 16 bytes, then part of the structure will be stored in stack.

No alt text provided for this image

Its size is 16 bytes, which means it should be placed entirely in the registers?R0-R3. Let's show this with an example:

No alt text provided for this image
No alt text provided for this image

As we can see by the example of the register?R2?in this case, the packaging works and two?uint16_t?fields of the structure are stored in this register. This is due to the peculiarities of storing the structure in memory (you can read more about this in a previous?post) and the fact that the fields of the structure?c?and?d?are not separate arguments and therefore the rule?one argument is one register?does not apply to them.

Now consider the case of a structure whose size is greater than 16 bytes:

No alt text provided for this image
No alt text provided for this image

In this case the the all struct can`t be stored in registers and some part of it (с and d members) was store in stack.

How arguments end up in registers and on the stack

How do all the arguments fall into the places reserved for them (registers or stack)? It's very simple: the compiler adds a special assembler code before calling each function, which deals with the distribution of arguments:

No alt text provided for this image
No alt text provided for this image

  1. Copying the d argument to the stack
  2. Copying the?c?argument to the stack
  3. Copying the b argument to R2-R3 registers
  4. Copying the a argument to R0-R1 registers
  5. Function call

This is another confirmation of the recommendation not to write functions with a large number of arguments, because in this way you not only worsen readability, but also actually increase the size occupied by the function in program memory and reduce the speed of access to this function.

Links

William Ribardo

Administrative Assistant at Health and Human Services

1 å¹´

One Character equals 8 bits. How do we as the caller pass to the callee a sensible query?

赞
回复
Anil Achoora

Lead Software Engineer at Siemens | Embedded | Cybersecurity

2 å¹´

This is really a nice artcle, most of the times when people had to use ARM inline assembly they will bump in to this situation that these registers are already used by the function . Thanks for writing this.

要查看或添加评论,请登录

Aliaksandr Kavalchuk的更多文章

  • С interview questions. Bit-fields

    С interview questions. Bit-fields

    Note: Almost all examples were compiled using the GCC 12.2 compiler for ARM Intro A Bit fields provide convenient…

    6 条评论
  • С interview questions. Static.

    С interview questions. Static.

    So one of the most common questions at firmware interviews is what does the keyword static mean and how is it used? The…

  • Bit operations in general and Arm bit banding in particular

    Bit operations in general and Arm bit banding in particular

    This article appeared in the process of writing a small library for working with the bit-banding mechanism for…

    2 条评论
  • С interview questions. Structure alignment in c

    С interview questions. Structure alignment in c

    This is one of the most popular interview questions. Calculate size of the next structure: And it is probably clear to…

  • Вопросы на cи собесе. Выравнивание элементов структуры.

    Вопросы на cи собесе. Выравнивание элементов структуры.

    Раз в прошлый раз мы затронули такую тему как выравнивание элементов структуры, то пожалуй разберем вопрос связанный…

    6 条评论
  • Вопросы на cи собесе. Flexible array member.

    Вопросы на cи собесе. Flexible array member.

    Update 1: Благодаря комментарию Nikita Divakov обновилось название статьи и в нем появилось нормальное название…

    7 条评论
  • Вопросы на Си собесе. Что такое static?

    Вопросы на Си собесе. Что такое static?

    Итак один из самых распространенных вопросов на собеседованиях по знанию языка С - что означает и как применяется…

    6 条评论

社区洞察

其他会员也浏览了