Bug 47602 - Permit inline asm to clobber PIC register
Summary: Permit inline asm to clobber PIC register
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.6.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-02-03 19:39 UTC by Ian Lance Taylor
Modified: 2015-02-24 20:01 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-02-03 23:49:50


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ian Lance Taylor 2011-02-03 19:39:53 UTC
This fails for i386 32-bit when using -fpic:

void foo() { asm volatile ("movl $0,%%ebx" : : : "ebx"); }

The compiler reports

foo.c:1:14: error: PIC register clobbered by ‘ebx’ in ‘asm’

This forces people to write their asm statements differently for PIC and non-PIC code.  That is not useful.  The compiler could save and restore the PIC register around the asm statement.  That would be more useful, and that is what we should do.
Comment 1 Andrew Pinski 2011-02-03 19:54:19 UTC
This was added on purpose.  See PR 8340.

*** This bug has been marked as a duplicate of bug 8340 ***
Comment 2 Ian Lance Taylor 2011-02-03 23:49:50 UTC
No, this is not a duplicate of PR 8340.  I am suggesting a different way of handling the situation, which would still produce correct code.  I am suggesting that when an asm clobbers the PIC register, that we explicitly save and restore the register around the asm.
Comment 3 Andrew Pinski 2011-02-03 23:52:33 UTC
(In reply to comment #2)
> No, this is not a duplicate of PR 8340.  I am suggesting a different way of
> handling the situation, which would still produce correct code.  I am
> suggesting that when an asm clobbers the PIC register, that we explicitly save
> and restore the register around the asm.

The reason why it is a dup is that we decided we did not want to fix it that way.  If you want to reopen the old bug that is a different story.
Comment 5 Andrew Pinski 2011-02-04 00:06:36 UTC
What happens on targets like PPC where r2 (the PIC register) is a fixed register should we save and restore it or error out.  I say we should error out.  Really I think it is a good thing to error out and force people to write their PIC vs no PIC inline-asm differently.  As it forces people to think about register pressure and such.
Comment 6 Ian Lance Taylor 2011-02-04 00:08:42 UTC
The old bug was about bad code generation, and that was fixed.  I don't think
it needs to be reopened.

I can not find any discussion about fixing this issue in any way other than
forbidding it.

I have no problem with forbidding clobbering fixed registers.  That is a related but distinct issue.

I do not think it is helpful to force people to consider pic vs. non-pic issues.  They can still consider them if they choose, but I do not think it is helpful to force them.
Comment 7 H.J. Lu 2011-02-04 01:42:03 UTC
(In reply to comment #6)
>
> I can not find any discussion about fixing this issue in any way other than
> forbidding it.
> 

EBX is fixed in PIC. If it is changed in asm, it should be saved and
restored in asm. Otherwise, non-leaf functions may not work properly
even if it is saved/restored in prologue/epilogue.
Comment 8 Ian Lance Taylor 2011-02-04 05:31:08 UTC
I'm suggesting saving and restoring it around the asm statement itself, not in the prologue and epilogue.
Comment 9 Eric Botcazou 2011-02-04 08:48:46 UTC
> I'm suggesting saving and restoring it around the asm statement itself, not in
> the prologue and epilogue.

Although the error was primarily RTH's idea, I still think it's very reasonable.
When you write inline asm, you're expecting a certain degree of control over the generated code; knowing that you're clobbering the PIC register can be useful, especially on a register-starved architecture like the x86.  If you stand by your clobbering, then writing the conditional save-and-restore code is trivial.
Comment 10 Ian Lance Taylor 2011-02-04 14:16:32 UTC
What advantage do we bring to our users by requiring them to be aware of the details of the PIC register when writing inline asm code?  Again, those who *are* aware of the PIC register have complete control.  But many people are able to write assembler code but have no idea what the PIC register is.  In what way are we helping them by forcing them to know about it?  How does that help them write inline assembler which, e.g., uses the cpuid instruction, or makes a kernel system call which passes a parameter in %ebx?
Comment 11 Andreas Schwab 2011-02-04 14:28:00 UTC
If you are writing assembler code you need to know your ABI in and out.
Comment 12 H.J. Lu 2011-02-04 15:01:56 UTC
(In reply to comment #10)
>
> what way are we helping them by forcing them to know about it?  How does that
> help them write inline assembler which, e.g., uses the cpuid instruction, or

Use <cpuid.h> provided by gcc.

> makes a kernel system call which passes a parameter in %ebx?

You can use syscall () or take a look at the C library source
to see how system call is inlined.
Comment 13 Eric Botcazou 2011-02-04 15:23:22 UTC
> In what way are we helping them by forcing them to know about it?  How does
> that help them write inline assembler which, e.g., uses the cpuid instruction,
> or makes a kernel system call which passes a parameter in %ebx?

In these cases, that won't probably help them indeed.  But, in other cases, like someone wanting to write very efficiently a hot loop in asm for a library, making it explicit that the %ebx register is not freely available like the others might help him to find the most efficient approach.  Maybe we could just warn though.
Comment 14 Paulo César Pereira de Andrade 2011-11-25 19:22:09 UTC
  In a first try on updating to valgrind 3.7.0 I run into this:

make[3]: Entering directory `/home/pcpa/rpm/BUILD/valgrind-3.7.0/coregrind'
x86_64-mandriva-linux-gnu-gcc -DHAVE_CONFIG_H -I. -I..  -I.. -I../include -I../VEX/pub -DVGA_x86=1 -DVGO_linux=1 -DVGP_x86_linux=1 -DVGPV_x86_linux_vanilla=1 -I../coregrind -DVG_LIBDIR="\"/usr/lib64/valgrind"\" -DVG_PLATFORM="\"x86-linux\""  -m32 -O2 -g -Wall -Wmissing-prototypes -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-declarations -Wno-format-zero-length -fno-strict-aliasing -fno-builtin -Wno-long-long -O2 -g -frecord-gcc-switches -Wstrict-aliasing=2 -pipe -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector --param=ssp-buffer-size=4 -fPIC -Wno-pointer-sign -fno-stack-protector -MT libcoregrind_x86_linux_a-syswrap-linux.o -MD -MP -MF .deps/libcoregrind_x86_linux_a-syswrap-linux.Tpo -c -o libcoregrind_x86_linux_a-syswrap-linux.o `test -f 'm_syswrap/syswrap-linux.c' || echo './'`m_syswrap/syswrap-linux.c
m_syswrap/syswrap-linux.c: In function 'run_a_thread_NORETURN':
m_syswrap/syswrap-linux.c:202:7: error: PIC register clobbered by 'ebx' in 'asm'
make[3]: *** [libcoregrind_x86_linux_a-syswrap-linux.o] Error 1

The code is like this:

static void run_a_thread_NORETURN ( Word tidW )
[...]
      /* We have to use this sequence to terminate the thread to
         prevent a subtle race.  If VG_(exit_thread)() had left the
         ThreadState as Empty, then it could have been reallocated,
         reusing the stack while we're doing these last cleanups.
         Instead, VG_(exit_thread) leaves it as Zombie to prevent
         reallocation.  We need to make sure we don't touch the stack
         between marking it Empty and exiting.  Hence the
         assembler. */
#if defined(VGP_x86_linux)
      asm volatile (
         "movl	%1, %0\n"	/* set tst->status = VgTs_Empty */
         "movl	%2, %%eax\n"    /* set %eax = __NR_exit */
         "movl	%3, %%ebx\n"    /* set %ebx = tst->os_state.exitcode */
         "int	$0x80\n"	/* exit(tst->os_state.exitcode) */
         : "=m" (tst->status)
         : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode)
         : "eax", "ebx"
      );
#elif defined(VGP_amd64_linux)

In valgrind 3.6.1 it works because it does not tell about the clobbered
registers.
Comment 15 Jan Seiffert 2011-12-24 15:54:23 UTC
As a heavy inline asm user myself, i can understand the pain to handle PIC yourself, but there is no way around that.

You can "accidentally" use the PIC register by a memory operand ("m"). Then the compiler can not save it for you.

Greetings
Jan
Comment 16 Kirill Yukhin 2014-10-13 17:27:21 UTC
Author: kyukhin
Date: Mon Oct 13 17:26:49 2014
New Revision: 216154

URL: https://gcc.gnu.org/viewcvs?rev=216154&root=gcc&view=rev
Log:

gcc/
	PR target/8340
	PR middle-end/47602
	PR rtl-optimization/55458
	* config/i386/i386.c (ix86_use_pseudo_pic_reg): New.
	(ix86_init_pic_reg): New.
	(ix86_select_alt_pic_regnum): Add check on pseudo register.
	(ix86_save_reg): Likewise.
	(ix86_expand_prologue): Remove PIC register initialization
	now performed in ix86_init_pic_reg.
	(ix86_output_function_epilogue): Add check on pseudo register.
	(set_pic_reg_ever_alive): New.
	(legitimize_pic_address): Replace df_set_regs_ever_live with new
	set_pic_reg_ever_alive.
	(legitimize_tls_address): Likewise.
	(ix86_pic_register_p): New check.
	(ix86_delegitimize_address): Add check on pseudo register.
	(ix86_expand_call): Insert move from pseudo PIC register to ABI
	defined REAL_PIC_OFFSET_TABLE_REGNUM.
	(TARGET_INIT_PIC_REG): New.
	(TARGET_USE_PSEUDO_PIC_REG): New.
	* config/i386/i386.h (PIC_OFFSET_TABLE_REGNUM): Return INVALID_REGNUM
	if pic_offset_table_rtx exists.
	* doc/tm.texi.in (TARGET_USE_PSEUDO_PIC_REG, TARGET_INIT_PIC_REG):
	Document.
	* doc/tm.texi: Regenerate.
	* function.c (assign_parms): Generate pseudo register for PIC.
	* init-regs.c (initialize_uninitialized_regs): Ignor pseudo PIC
	register.
	* ira-color.c (color_pass): Add check on pseudo register.
	* ira-emit.c (change_loop): Don't create copies for PIC pseudo
	register.
	* ira.c (split_live_ranges_for_shrink_wrap): Add check on pseudo
	register.
	(ira): Add target specific PIC register initialization.
	(do_reload): Keep PIC pseudo register.
	* lra-assigns.c (spill_for): Add checks on pseudo register.
	* lra-constraints.c (contains_symbol_ref_p): New.
	(lra_constraints): Enable lra risky transformations when PIC is pseudo
	register.
	* shrink-wrap.c (try_shrink_wrapping): Add check on pseudo register.
	* target.def (use_pseudo_pic_reg): New.
	(init_pic_reg): New.

gcc/testsuite/
	PR target/8340
	PR middle-end/47602
	PR rtl-optimization/55458
	* gcc.target/i386/pic-1.c: Remove dg-error as test should pass now.
	* gcc.target/i386/pr55458.c: Likewise.
	* gcc.target/i386/pr47602.c: New.
	* gcc.target/i386/pr23098.c: Move to XFAIL.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/config/i386/i386.c
    trunk/gcc/config/i386/i386.h
    trunk/gcc/doc/tm.texi
    trunk/gcc/doc/tm.texi.in
    trunk/gcc/function.c
    trunk/gcc/init-regs.c
    trunk/gcc/ira-color.c
    trunk/gcc/ira-emit.c
    trunk/gcc/ira.c
    trunk/gcc/lra-assigns.c
    trunk/gcc/lra-constraints.c
    trunk/gcc/shrink-wrap.c
    trunk/gcc/target.def
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gcc.target/i386/pic-1.c
    trunk/gcc/testsuite/gcc.target/i386/pr23098.c
    trunk/gcc/testsuite/gcc.target/i386/pr55458.c
Comment 17 Jeffrey A. Law 2015-02-24 20:01:49 UTC
Now that the PIC register is a pseudo for i686, this "just works".