Search code examples
x86elfrelocation

What's the difference between R_386_GOT32 and R_386_GOT32X?


I've found a lot of documentation for R_386_GOT32, but not R_386_GOT32X. I was able to find https://github.com/hjl-tools/x86-psABI/wiki/intel386-psABI-draft.pdf which shows the calculation for R_386_GOT32X, but it looks to be the same as that for R_386_GOT32

R_386_GOT32 | 3 | word32 | G + A - GOT / G + A†

R_386_GOT32X | 43 | word32 | G + A - GOT / G + A†


Solution

  • Both relocations have the same effect and the calculations are the same, but R_386_GOT32X relocations allow the linker to optimize the instructions used for the calculation, using immediate operands instead of memory operands under certain conditions.

    H. J. Lu (Intel engineer who introduced R_386_GOT32X) explains it in the IA32 System V ABI mailing list:

    X86 instruction encoding supports converting some instructions on memory operand with GOT32 relocation against symbol, foo, into a different form on immediate operand if foo is defined locally. Those instructions are:

    call *foo@GOT[(%reg)]       => nop call foo or call foo nop
    jmp *foo@GOT[(%reg)]        => jmp foo nop 
    mov foo@GOT[(%reg1)], %reg2 => lea foo[@GOTOFF(%reg1)], %reg2
    

    When osition-independent code is disable,

    test %reg1, foo@GOT[(%reg2)] => test $foo, %reg1 binop
    foo@GOT[(%reg1)], %reg2      => binop $foo, %reg2
    

    where binop is one of adc, add, and, cmp, or, sbb, sub, xor instructions.

    I am proposing to add a new relocation, R_386_GOT32X, to i386 psABI. Instead of generating R_386_GOT32 relocation agasint foo for foo@GOT(%reg), we generate R_386_GOT32X. R_386_GOT32X relocation can also be used without the base register for the global offset table, foo@GOT, when position-independent code is disable. In this case, the static base address of the global offset table will be used instead. Linker can treat R_386_GOT32X the same as R_386_GOT32 or it can perform the transformations listed above.

    Indeed, according to the IA32 System V ABI document you linked (section A.2):

    Optimize R_386_GOT32X Relocation

    The Intel386 instruction encoding supports converting certain instructions on memory operand with R_386_GOT32X relocation against symbol, foo, into a different form on immediate operand if foo is defined locally:

    Convert call, jmp and mov Convert memory operand of call, jmp and mov into immediate operand.

    Memory Operand Immediate Operand
    call *foo@GOT(%reg) nop call foo
    call *foo@GOT(%reg) call foo nop
    jmp *foo@GOT(%reg) jmp foo nop
    mov foo@GOT(%reg1), %reg2 lea foo@GOTOFF(%reg1), %reg2

    Convert Test and Binop Convert memory operand of call, jmp, mov, test and binop into immediate operand, where binop is one of adc, add, and, cmp, or, sbb, sub, xor instructions, when position-independent code is disabled.

    Memory Operand Immediate Operand
    call *foo@GOT nop call foo
    call *foo@GOT call foo nop
    jmp *foo@GOT jmp foo nop
    mov foo@GOT, %reg mov $foo, %reg
    test %reg, foo@GOT test $foo, %reg
    binop foo@GOT, %reg binop $foo, %reg
    call *foo@GOT(%reg) nop call foo
    call *foo@GOT(%reg) call foo nop
    jmp *foo@GOT(%reg) jmp foo nop
    mov foo@GOT(%reg1), %reg2 mov $foo, %reg2
    test %reg1, name@GOT(%reg2) test $foo, %reg1
    binop name@GOT(%reg1), %reg2 binop $foo, %reg2