https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118497
Bug ID: 118497 Summary: [15 Regression] Worse code generated on i686-linux since r15-1619 Product: gcc Version: 15.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: jakub at gcc dot gnu.org Target Milestone: --- Since r15-1619-g3b9b8d6cfdf59337f4b7ce10ce92a98044b2657b we emit one instruction longer code for -O2 -m32 -fpic extern void crosscall2 (void (*fn) (void *, int), void *, int); extern void _cgo_panic (void *, int); extern void _cgo_allocate (void *, int); void callPanic (void) { struct { const char *p; } a; a.p = "panic from C"; crosscall2 (_cgo_panic, &a, sizeof a); *(int*) 1 = 1; } The function makes a function call, so in the ia32 ABI at the crosscall2@plt call %ebx register must hold the _GLOBAL_OFFSET_TABLE_ value. Before r15-1619 we just emitted load of that into %ebx and used %ebx as the PIC register even for @GOT loads, but starting with that revision we load the PIC register into %eax instead and use %eax as PIC register for @GOT loads and then copy %eax into %ebx for the call. So .globl callPanic .type callPanic, @function callPanic: + call __x86.get_pc_thunk.ax + addl $_GLOBAL_OFFSET_TABLE_, %eax pushl %ebx - call __x86.get_pc_thunk.bx - addl $_GLOBAL_OFFSET_TABLE_, %ebx subl $28, %esp - leal .LC0@GOTOFF(%ebx), %eax - movl %eax, 16(%esp) + leal .LC0@GOTOFF(%eax), %edx + movl %eax, %ebx + movl %edx, 16(%esp) pushl $4 - leal 20(%esp), %eax - pushl %eax - pushl _cgo_panic@GOT(%ebx) + leal 20(%esp), %edx + pushl %edx + pushl _cgo_panic@GOT(%eax) call crosscall2@PLT movl $1, 1 addl $40, %esp popl %ebx ret If a function does PLT calls, I think loading PIC register into %ebx and keeping it there is most likely best.