Difference in data alignment in struct vs parameter?

余生颓废 提交于 2020-01-06 13:09:12

问题


Given the following code:

typedef struct tagRECT {
  int left;
  int top;
  int right;
  int bottom;
} RECT;

extern int Func(RECT *a, int b, char *c, int d, char e, long f, int g, int h, int i, int j);

int main() {

}

void gui() {
    RECT x = {4, 5, 6, 7};
    Func(&x, 1, 0, 3, 4, 5, 6, 7, 8, 9);
}

This is the assembly generated gcc x86_64 presumably on linux (I used compiler explorer).

main:
  mov eax, 0
  ret
gui:
  push rbp
  mov rbp, rsp
  sub rsp, 16
  ; RECT x assignment
  mov DWORD PTR [rbp-16], 4
  mov DWORD PTR [rbp-12], 5
  mov DWORD PTR [rbp-8], 6
  mov DWORD PTR [rbp-4], 7

  ; parameters
  lea rax, [rbp-16]
  push 9
  push 8
  push 7
  push 6
  mov r9d, 5
  mov r8d, 4
  mov ecx, 3
  mov edx, 0
  mov esi, 1
  mov rdi, rax
  call Func
  add rsp, 32
  nop
  leave
  ret

It can be seen that the int in the struct are aligned by 4 bytes. But the last 4 parameters to the function, all int are pushd to the stack which means they were aligned by 8 bytes. Why this inconsistency?


回答1:


stack slots are 8 bytes in x86-64 calling conventions like the x86-64 System V calling convention you're using, because 32-bit push/pop is impossible, and to make it easier to keep it 16-byte aligned. See What are the calling conventions for UNIX & Linux system calls on i386 and x86-64 (it also covers function-calling conventions, as well as system-calling conventions. Where is the x86-64 System V ABI documented?.

mov works just fine, though, so it would have been a valid design to make 4 bytes the minimum unit for stack args. (Unlike x86-16 where SP-relative addressing modes were impossible). But unless you introduce padding rules, then you could have misaligned 8-byte args. So giving every arg at least 8-byte alignment was probably part of the motivation. (Although there are padding rules to guarantee that __m128 args have 16-byte alignment, and __m256 have 32-byte, etc. And presumably also for over-aligned structs, like struct { alignas(64) char b[256]; };.

Only 4-byte slots would break more easily for functions without prototypes, and maybe make variadic functions more complex, but x86-64 System V already passes larger objects by value on the stack, so a stack arg may take more than one 8-byte "stack slot".

(Unlike Windows x64 which passes by hidden reference so every arg is exactly one stack slot. It even reserves 32 bytes of shadow space so a variadic function can spill its register args into the shadow space and create a full array of all the args.)



来源:https://stackoverflow.com/questions/51564190/difference-in-data-alignment-in-struct-vs-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!