Bug 41055 - libgcc functions and -mregparm don't work well together
Summary: libgcc functions and -mregparm don't work well together
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.3.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-08-13 14:45 UTC by Patrick Georgi
Modified: 2019-03-01 00:18 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Test case (C) (142 bytes, text/plain)
2019-03-01 00:00 UTC, H. Peter Anvin
Details
Test case (preprocessed) (161 bytes, text/plain)
2019-03-01 00:00 UTC, H. Peter Anvin
Details
Test case (assembly output) (268 bytes, text/plain)
2019-03-01 00:03 UTC, H. Peter Anvin
Details
Test code (object output) (412 bytes, application/octet-stream)
2019-03-01 00:03 UTC, H. Peter Anvin
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Patrick Georgi 2009-08-13 14:45:52 UTC
When building code with -mregparm=x on i?86 which uses libgcc functions (eg. udivdi3), the calls to the libgcc functions use the calling convention as given by mregparm, even though libgcc is internal to the compiler (and the user has no ultimate control about when it is used).

Adding the compiler-native calling convention as regparm attribute to all calls that are synthesized by the compiler might fix the problem.

The following shell script exhibits the problem.

cat > test.c << EOF
int main() {
 long long a= 4000000000;
 return a / 43937;
}
EOF

gcc -S test.c
mv test.s test.default.s

gcc -mregparm=3 -S test.c
mv test.s test.mregparm3.s

diff -u test.default.s test.mregparm3.s
exit 0
# there should be no difference in the calling convention
# as __divdi3 is taken from libgcc, but I get the result:
--- test.default.s	Do. Aug 13 15:47:28 2009
+++ test.mregparm3.s	Do. Aug 13 15:47:28 2009
 -18,10 +18,9 @@
 	movl	$0, -4(%ebp)
 	movl	-8(%ebp), %eax
 	movl	-4(%ebp), %edx
+	subl	$8, %esp
 	pushl	$0
 	pushl	$43937
-	pushl	%edx
-	pushl	%eax
 	call	__divdi3
 	addl	$16, %esp
 	leave
Comment 1 Richard Biener 2009-08-13 14:58:26 UTC
-mregparm changes the ABI, you have to rebuild libgcc with -mregparm to be
able to use it.
Comment 2 Stefan Reinauer 2009-08-13 15:08:59 UTC
So we have to rebuild parts of the compiler in order to get a working compiler, depending on the compiler flags we use? That sounds pretty broken to me. In my opinion, since -mregparm is a gcc run time option, not a compile time option, the compiler should provide libgcc for every possible ABI and choose among those.

Closing this bug is especially weird since #12081 implies that building the compiler with -mregparm=3 is broken.
Comment 3 Patrick Georgi 2009-08-13 15:10:53 UTC
(In reply to comment #1)
> -mregparm changes the ABI, you have to rebuild libgcc with -mregparm to be
> able to use it.
> 

I agree with that notion for general purpose libraries as used by the user. But libgcc is an implementation artefact of GCC. I'd prefer not to use it, but GCC forces me to.

If I use __divdi3 myself, GCC can expect that I fix up the call myself (using some __attribute__((regparm))), but if GCC uses it, I think it's not to much to ask for it to fix it up itself (as I don't have the means to do so, short of rewriting assembler code)

I see three good solutions:
1. GCC calls its own libgcc calls in a proper way (and it should be able to do so, if I as a user can change calling conventions per function call)
2. It refuses to use libgcc with mregparm, as it will break.
3. GCC supports multiple libgccs, choosing the right one automatically.

My guess is that solution 1 is the easiest. Hacks like http://trac.nchc.org.tw/grid/browser/gpfs_3.1_ker2.6.20/lpp/mmfs/src/gpl-linux/mmwrap.c shouldn't be necessary.
Comment 4 Michael Matz 2009-08-13 15:36:45 UTC
I agree with the reporters.  libgcc isn't some random library, GCC should call
it correctly even in the presence of -mregparm.
Comment 5 H. Peter Anvin 2019-03-01 00:00:00 UTC
Created attachment 45858 [details]
Test case (C)
Comment 6 H. Peter Anvin 2019-03-01 00:00:52 UTC
Created attachment 45860 [details]
Test case (preprocessed)
Comment 7 H. Peter Anvin 2019-03-01 00:03:01 UTC
Created attachment 45861 [details]
Test case (assembly output)
Comment 8 H. Peter Anvin 2019-03-01 00:03:32 UTC
Created attachment 45862 [details]
Test code (object output)
Comment 9 H. Peter Anvin 2019-03-01 00:18:22 UTC
I can confirm this bug is still present as of gcc 8.2.1.

I have attached a test case which clearly shows __udivdi3 called with the regparm convention, but libgcc definitely does not expect it:

objdump -dr `gcc -m32 -march=i386 -mregparm=3 -O3 -fomit-frame-pointer --print-libgcc`

00000000 <__udivdi3>:
   0:   f3 0f 1e fb             endbr32 
   4:   55                      push   %ebp
   5:   57                      push   %edi
   6:   56                      push   %esi
   7:   53                      push   %ebx
   8:   83 ec 1c                sub    $0x1c,%esp
   b:   8b 54 24 3c             mov    0x3c(%esp),%edx
   f:   8b 6c 24 30             mov    0x30(%esp),%ebp
  13:   8b 74 24 34             mov    0x34(%esp),%esi
  17:   8b 5c 24 38             mov    0x38(%esp),%ebx
...

As far as I can tell, there are four possible options:

a. Build a libgcc for any combination of runtime options.
b. Add multiple functions to libgcc for each combination of runtime options which matter.
c. Force using a single ABI for libgcc functions (in which case it might as well use the most efficient ABI, e.g. -mregparm=3 -freg-struct-return); as the libgcc functions are private to gcc anyway there is no reason they need to use the main calling convention.
d. Emit these functions in a link-once section, similar to the way __x86.get_pc_thunk.* are generated. This has upsides and downsides: the upsides are that they are inherently correct, that they can rely on arch/optimize flags, a dynamic library can't get out of sync with the compiler if these functions are changed, and these functions can be marked hidden, which means that they can be called directly. Downsides are link time and some heavy lifting in implementation.

It also means that each dynamic library carries its own copy, but since libgcc already marks its symbols HIDDEN, this is already the case.