[4/4] x86: Add 'V' register operand modifier

Message ID 20180112131549.18143-5-hjl.tools@gmail.com
State New
Headers show
Series
  • x86: CVE-2017-5715, aka Spectre
Related show

Commit Message

H.J. Lu Jan. 12, 2018, 1:15 p.m.
Add 'V', a special modifier which prints the name of the full integer
register without '%'.  For

extern void (*func_p) (void);

void
foo (void)
{
  asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
}

it generates:

foo:
	movq	func_p(%rip), %rax
	call	__x86_indirect_thunk_rax
	ret

gcc/

	* config/i386/i386.c (print_reg): Print the name of the full
	integer register without '%'.
	(ix86_print_operand): Handle 'V'.
	 * doc/extend.texi: Document 'V' modifier.

gcc/testsuite/

	* gcc.target/i386/indirect-thunk-register-4.c: New test.
---
 gcc/config/i386/i386.c                                    | 13 ++++++++++++-
 gcc/doc/extend.texi                                       |  3 +++
 gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c | 13 +++++++++++++
 3 files changed, 28 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c

Comments

Jan Hubicka Jan. 12, 2018, 6 p.m. | #1
> Add 'V', a special modifier which prints the name of the full integer
> register without '%'.  For
> 
> extern void (*func_p) (void);
> 
> void
> foo (void)
> {
>   asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
> }
> 
> it generates:
> 
> foo:
> 	movq	func_p(%rip), %rax
> 	call	__x86_indirect_thunk_rax
> 	ret
> 
> gcc/
> 
> 	* config/i386/i386.c (print_reg): Print the name of the full
> 	integer register without '%'.
> 	(ix86_print_operand): Handle 'V'.
> 	 * doc/extend.texi: Document 'V' modifier.

Seems reasonable. Purpose of this is to make posible to call thunks
from asm statements, right?

Honza
> 
> gcc/testsuite/
> 
> 	* gcc.target/i386/indirect-thunk-register-4.c: New test.
> ---
>  gcc/config/i386/i386.c                                    | 13 ++++++++++++-
>  gcc/doc/extend.texi                                       |  3 +++
>  gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c | 13 +++++++++++++
>  3 files changed, 28 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
> 
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index 9ffcb69d6d7..e69135d7191 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -17617,6 +17617,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
>     If CODE is 'h', pretend the reg is the 'high' byte register.
>     If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
>     If CODE is 'd', duplicate the operand for AVX instruction.
> +   If CODE is 'V', print naked full integer register name without %.
>   */
>  
>  void
> @@ -17627,7 +17628,7 @@ print_reg (rtx x, int code, FILE *file)
>    unsigned int regno;
>    bool duplicated;
>  
> -  if (ASSEMBLER_DIALECT == ASM_ATT)
> +  if (ASSEMBLER_DIALECT == ASM_ATT && code != 'V')
>      putc ('%', file);
>  
>    if (x == pc_rtx)
> @@ -17679,6 +17680,14 @@ print_reg (rtx x, int code, FILE *file)
>        return;
>      }
>  
> +  if (code == 'V')
> +    {
> +      if (GENERAL_REGNO_P (regno))
> +	msize = GET_MODE_SIZE (word_mode);
> +      else
> +	error ("'V' modifier on non-integer register");
> +    }
> +
>    duplicated = code == 'd' && TARGET_AVX;
>  
>    switch (msize)
> @@ -17798,6 +17807,7 @@ print_reg (rtx x, int code, FILE *file)
>     & -- print some in-use local-dynamic symbol name.
>     H -- print a memory address offset by 8; used for sse high-parts
>     Y -- print condition for XOP pcom* instruction.
> +   V -- print naked full integer register name without %.
>     + -- print a branch hint as 'cs' or 'ds' prefix
>     ; -- print a semicolon (after prefixes due to bug in older gas).
>     ~ -- print "i" if TARGET_AVX2, "f" otherwise.
> @@ -18021,6 +18031,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
>  	case 'X':
>  	case 'P':
>  	case 'p':
> +	case 'V':
>  	  break;
>  
>  	case 's':
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index f120b2a1429..dce808f1eab 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -9292,6 +9292,9 @@ The table below shows the list of supported modifiers and their effects.
>  @tab @code{2}
>  @end multitable
>  
> +@code{V} is a special modifier which prints the name of the full integer
> +register without @code{%}.
> +
>  @anchor{x86floatingpointasmoperands}
>  @subsubsection x86 Floating-Point @code{asm} Operands
>  
> diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
> new file mode 100644
> index 00000000000..f0cd9b75be8
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
> @@ -0,0 +1,13 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mindirect-branch=keep -fno-pic" } */
> +
> +extern void (*func_p) (void);
> +
> +void
> +foo (void)
> +{
> +  asm("call __x86_indirect_thunk_%V0" : : "a" (func_p));
> +}
> +
> +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_eax" { target ia32 } } } */
> +/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_rax" { target { ! ia32 } } } } */
> -- 
> 2.14.3
H.J. Lu Jan. 12, 2018, 6:10 p.m. | #2
On Fri, Jan 12, 2018 at 10:00 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
>> Add 'V', a special modifier which prints the name of the full integer
>> register without '%'.  For
>>
>> extern void (*func_p) (void);
>>
>> void
>> foo (void)
>> {
>>   asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
>> }
>>
>> it generates:
>>
>> foo:
>>       movq    func_p(%rip), %rax
>>       call    __x86_indirect_thunk_rax
>>       ret
>>
>> gcc/
>>
>>       * config/i386/i386.c (print_reg): Print the name of the full
>>       integer register without '%'.
>>       (ix86_print_operand): Handle 'V'.
>>        * doc/extend.texi: Document 'V' modifier.
>
> Seems reasonable. Purpose of this is to make posible to call thunks
> from asm statements, right?
>

Yes.
Florian Weimer Jan. 13, 2018, 4:28 p.m. | #3
* H. J. Lu:

> On Fri, Jan 12, 2018 at 10:00 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
>>> Add 'V', a special modifier which prints the name of the full integer
>>> register without '%'.  For
>>>
>>> extern void (*func_p) (void);
>>>
>>> void
>>> foo (void)
>>> {
>>>   asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
>>> }

>> Seems reasonable. Purpose of this is to make posible to call thunks
>> from asm statements, right?
>
> Yes.

Can you actually do this in practice?  What about the red zone and CFI
annotations?
H.J. Lu Jan. 13, 2018, 4:36 p.m. | #4
On Sat, Jan 13, 2018 at 8:28 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
> * H. J. Lu:
>
>> On Fri, Jan 12, 2018 at 10:00 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
>>>> Add 'V', a special modifier which prints the name of the full integer
>>>> register without '%'.  For
>>>>
>>>> extern void (*func_p) (void);
>>>>
>>>> void
>>>> foo (void)
>>>> {
>>>>   asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
>>>> }
>
>>> Seems reasonable. Purpose of this is to make posible to call thunks
>>> from asm statements, right?
>>
>> Yes.
>
> Can you actually do this in practice?  What about the red zone and CFI
> annotations?

This is used by kernel, which doesn't use red-zone.  David, does it
work for kernel?
David Woodhouse Jan. 13, 2018, 4:41 p.m. | #5
On Sat, 2018-01-13 at 08:36 -0800, H.J. Lu wrote:
> On Sat, Jan 13, 2018 at 8:28 AM, Florian Weimer <fw@deneb.enyo.de> wrote:
> > 
> > * H. J. Lu:
> > 
> > > 
> > > On Fri, Jan 12, 2018 at 10:00 AM, Jan Hubicka <hubicka@ucw.cz> wrote:
> > > > 
> > > > > 
> > > > > Add 'V', a special modifier which prints the name of the full integer
> > > > > register without '%'.  For
> > > > > 
> > > > > extern void (*func_p) (void);
> > > > > 
> > > > > void
> > > > > foo (void)
> > > > > {
> > > > >   asm ("call __x86_indirect_thunk_%V0" : : "a" (func_p));
> > > > > }
> > > 
> > > > 
> > > > Seems reasonable. Purpose of this is to make posible to call thunks
> > > > from asm statements, right?
> > >
> > > Yes.
> >
> > Can you actually do this in practice?  What about the red zone and CFI
> > annotations?
>
> This is used by kernel, which doesn't use red-zone.  David, does it
> work for kernel?

Yes. I did start by using it everywhere, but Linus asked me to put the
thunks inline instead. Now we only have one instance of it left, in the
CALL_SPEC macro used for inline asm:
http://git.infradead.org/users/dwmw2/linux-retpoline.git/blob/76b043848fd22dbf7f8bf3a1452f8c70d557b860:/arch/x86/include/asm/nospec-branch.h#l89

It's used from places like this:
http://git.infradead.org/users/dwmw2/linux-retpoline.git/commitdiff/e70e5892b28c18f517f29ab6e83bd57705104b31
http://git.infradead.org/users/dwmw2/linux-retpoline.git/commitdiff/ea08816d5b185ab3d09e95e393f265af54560350

Patch

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 9ffcb69d6d7..e69135d7191 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -17617,6 +17617,7 @@  put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
    If CODE is 'h', pretend the reg is the 'high' byte register.
    If CODE is 'y', print "st(0)" instead of "st", if the reg is stack op.
    If CODE is 'd', duplicate the operand for AVX instruction.
+   If CODE is 'V', print naked full integer register name without %.
  */
 
 void
@@ -17627,7 +17628,7 @@  print_reg (rtx x, int code, FILE *file)
   unsigned int regno;
   bool duplicated;
 
-  if (ASSEMBLER_DIALECT == ASM_ATT)
+  if (ASSEMBLER_DIALECT == ASM_ATT && code != 'V')
     putc ('%', file);
 
   if (x == pc_rtx)
@@ -17679,6 +17680,14 @@  print_reg (rtx x, int code, FILE *file)
       return;
     }
 
+  if (code == 'V')
+    {
+      if (GENERAL_REGNO_P (regno))
+	msize = GET_MODE_SIZE (word_mode);
+      else
+	error ("'V' modifier on non-integer register");
+    }
+
   duplicated = code == 'd' && TARGET_AVX;
 
   switch (msize)
@@ -17798,6 +17807,7 @@  print_reg (rtx x, int code, FILE *file)
    & -- print some in-use local-dynamic symbol name.
    H -- print a memory address offset by 8; used for sse high-parts
    Y -- print condition for XOP pcom* instruction.
+   V -- print naked full integer register name without %.
    + -- print a branch hint as 'cs' or 'ds' prefix
    ; -- print a semicolon (after prefixes due to bug in older gas).
    ~ -- print "i" if TARGET_AVX2, "f" otherwise.
@@ -18021,6 +18031,7 @@  ix86_print_operand (FILE *file, rtx x, int code)
 	case 'X':
 	case 'P':
 	case 'p':
+	case 'V':
 	  break;
 
 	case 's':
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f120b2a1429..dce808f1eab 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -9292,6 +9292,9 @@  The table below shows the list of supported modifiers and their effects.
 @tab @code{2}
 @end multitable
 
+@code{V} is a special modifier which prints the name of the full integer
+register without @code{%}.
+
 @anchor{x86floatingpointasmoperands}
 @subsubsection x86 Floating-Point @code{asm} Operands
 
diff --git a/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
new file mode 100644
index 00000000000..f0cd9b75be8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/indirect-thunk-register-4.c
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=keep -fno-pic" } */
+
+extern void (*func_p) (void);
+
+void
+foo (void)
+{
+  asm("call __x86_indirect_thunk_%V0" : : "a" (func_p));
+}
+
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "call\[ \t\]*__x86_indirect_thunk_rax" { target { ! ia32 } } } } */