简体   繁体   中英

Layout of structs in Linux/x86-64 syscalls for assembly programmers?

A number of linux/x86-64 syscalls accept pointers to structs as arguments.

For example the second parameter of stat(2) is struct stat* ...

   struct stat {
       dev_t     st_dev;     /* ID of device containing file */
       ino_t     st_ino;     /* inode number */
       mode_t    st_mode;    /* protection */
       nlink_t   st_nlink;   /* number of hard links */
       uid_t     st_uid;     /* user ID of owner */
       gid_t     st_gid;     /* group ID of owner */
       dev_t     st_rdev;    /* device ID (if special file) */
       off_t     st_size;    /* total size, in bytes */
       blksize_t st_blksize; /* blocksize for file system I/O */
       blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
       time_t    st_atime;   /* time of last access */
       time_t    st_mtime;   /* time of last modification */
       time_t    st_ctime;   /* time of last status change */
   };

This means that if you want to call the syscall from pure assembly than you have to know the rules about how big each type is, and whether there is any padding in between members for alignment purposes, and so on.

Does the C standard leave this open to be (compiler) implementation defined or can it be determined from the standard (assuming the primitive type sizes are known)?

If it is left open, does the kernel or the x86-64 architecture define it in anyway? Or is it just a matter of which compiler the kernel happened to be compiled with?

(That is given some member of the struct I need to calculate the starting offset of that member relative to the address of the struct)

The layout of structs is not defined in the C standard, but in the ABI definition, in your case the System V AMD64 ABI. That is, in general the layout is OS dependent, and all compilers targeting that OS must conform to the ABI (though most will have options to generate different layout if you know what you are doing). The ABI also defines how parameters are passed to functions, how values are returned, which registers must be preserved across calls, and so on.

The ABI definition you need should be available on http://www.x86-64.org/ (seems to be down)

Under Linux/x86-64:

A byte is 8 bits. Sizes and memory addresses are in 1 byte units.

Primitive Types

Primitive Types have an alignment equal to their size:

The primitive type sizes (and alignments) are:

bool 1
char 1
short 2
int 4
long 8
long long 8
__int128 16
void* 8
float 4
double 8
long double 16
__float128 16
__m64 8
__m128 16

Structs, Unions and Arrays

  • Structs (and unions) alignment is that of the maximum alignment of any of their components.

  • Each struct member is assigned to the lowest available offset with the appropriate alignment.

  • The size of a struct is rounded up to the nearest multiple of its alignment.

  • Structure and union objects can require padding to meet size and alignment constraints. The contents of any padding is undefined.

  • An array of less than 16 bytes has the alignment of its element type.

  • An array of 16 bytes or longer has alignment of the higher of (a) 16; and (b) the alignment of its element type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM