Why doesn't GCC use partial registers?

前端 未结 3 1381
[愿得一人]
[愿得一人] 2020-11-22 01:01

Disassembling write(1,\"hi\",3) on linux, built with gcc -s -nostdlib -nostartfiles -O3 results in:

ba03000000     mov edx, 3 ; tha         


        
3条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-22 01:15

    In fact, gcc very often uses partial registers. If you look generated code, you'll find lots of cases where partial registers are used.

    The short answer for your particular case, is because gcc always sign or zero-extends arguments to 32-bits when calling a C ABI function.

    The de-facto SysV x86 and x86-64 ABI adopted by gcc and clang requires that parameters smaller than 32-bits are zero or sign-extended to 32-bits. Interestingly, they don't need to be extended all the way to 64-bit.

    So for a function like the following on a 64-bit platform SysV ABI platform:

    void foo(short s) {
     ...
    }
    

    ... the argument s is passed in rdi and the bits of s will be as follows (but see my caveat below regarding icc):

      bits 0-31:  SSSSSSSS SSSSSSSS SPPPPPPP PPPPPPPP
      bits 32-63: XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX
      where:
      P: the bottom 15 bits of the value of `s`
      S: the sign bit of `s` (extended into bits 16-31)
      X: arbitrary garbage
    

    The code for foo can depend on the S and P bits, but not on the X bits, which may be anything.

    Similarly, for foo_unsigned(unsigned short u), you'd have 0 in bits 16-31, but it would otherwise be identical.

    Note that I said defacto - because it actually isn't really documented what to do for smaller return types, but you can see Peter's answer here for details. I also asked a related question here.

    After some further testing, I concluded that icc actually breaks this defacto standard. gcc and clang seem to adhere to it, but gcc only in a conservative way: when calling a function, it does zero/sign-extend arguments to 32-bits, but in its function implementations in doesn't depend on the caller doing it. clang implements functions that depend on the caller extending the parameters to 32-bits. So in fact clang and icc are mutually incompatible even for plain C functions if they have any parameters smaller than int.

提交回复
热议问题