I was researching the calling convention of x86_64 that's used on OSX and was reading the section called "Aggregates and Unions" in the System V x86-64 ABI standard). It mention arrays and I figured that was like a fixed length c array, e.g. int[5]
.
I went down to "3.2.3 Parameter Passing" to read about how arrays were passed and if I'm understanding correctly, something like uint8_t[3]
should be passed in registers as it's smaller than the four eightbyte limit imposed by rule 1 of the classification of aggregate types (page 18 near the bottom).
After compiling I see that instead it's being passed as a pointer. (I'm compiling with clang-703.0.31 from Xcode 7.3.1 on OSX 10.11.6).
The example source I was using to compile is as follows:
#include <stdio.h>
#define type char
extern void doit(const type[3]);
extern void doitt(const type[5]);
extern void doittt(const type[16]);
extern void doitttt(const type[32]);
extern void doittttt(const type[40]);
int main(int argc, const char *argv[]) {
const char a[3] = { 1, 2, 3 };
const char b[5] = { 1, 2, 3, 4, 5 };
const char c[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1 };
const char d[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1 };
const char e[40] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
doit(a);
doitt(b);
doittt(c);
doitttt(d);
doittttt(e);
}
I dump that in a file named a.c
and use the following command to compile: clang -c a.c -o a.o
. I use otool to analyze the assembly generated (by running otool -tV a.o
) and get the following output:
a.o:
(__TEXT,__text) section
_main:
0000000000000000 pushq %rbp
0000000000000001 movq %rsp, %rbp
0000000000000004 subq $0x10, %rsp
0000000000000008 leaq _main.a(%rip), %rax
000000000000000f movl %edi, -0x4(%rbp)
0000000000000012 movq %rsi, -0x10(%rbp)
0000000000000016 movq %rax, %rdi
0000000000000019 callq _doit
000000000000001e leaq _main.b(%rip), %rdi
0000000000000025 callq _doitt
000000000000002a leaq _main.c(%rip), %rdi
0000000000000031 callq _doittt
0000000000000036 leaq _main.d(%rip), %rdi
000000000000003d callq _doitttt
0000000000000042 leaq _main.e(%rip), %rdi
0000000000000049 callq _doittttt
000000000000004e xorl %eax, %eax
0000000000000050 addq $0x10, %rsp
0000000000000054 popq %rbp
0000000000000055 retq
Or equivalently, here it is on the Godbolt compiler explorer with clang3.7, which targets Linux which uses the same ABI.
So, I was wondering if anyone could lead me to what data types in C11 apply to arrays. (It looks like clang defaults to using C11 - see the blurb here right under C99 inline function).
I also did a similar investigation with ARM and found similar results, even though the ARM standard also specifies there exists an array aggregate type.
Also, is there somewhere in some standard that it's specified that a fixed length array is to be treated as a pointer?
void func(int param[]);
, the type ofparam
is adjusted fromint[]
toint*
. (This is a distinct rule from the one that specifies implicit conversion of array expressions to pointers.) – Cruciatesizeof
,&
, and a string literal in an initializer used to initialize an array object); argument passing just happens to be one of the contexts where the conversion does happen. – Cruciate&
, string literal in an initializer). EDIT: Didnt see your response to me above - apologies. It looks like that fact you stated is just known because you're very familiar with the standard based on how 6.7.6.3 paragraph 7 is worded. – Recrimination_Alignof
is incorrect in that draft, corrected in the published ISO C11 standard.) – Cruciate