diff mbox series

[kvm-unit-tests,v3,11/17] x86 UEFI: Convert x86 test cases to PIC

Message ID 20211004204931.1537823-12-zxwang42@gmail.com (mailing list archive)
State New, archived
Headers show
Series x86_64 UEFI and AMD SEV/SEV-ES support | expand

Commit Message

Zixuan Wang Oct. 4, 2021, 8:49 p.m. UTC
From: Zixuan Wang <zixuanwang@google.com>

UEFI loads EFI applications to dynamic runtime addresses, so it requires
all applications to be compiled as PIC (position independent code). PIC
does not allow the usage of compile time absolute address.

This commit converts multiple x86 test cases to PIC so they can compile
and run in UEFI:

- x86/cet.efi

- x86/emulator.c: x86/emulator.c depends on lib/x86/usermode.c. But
usermode.c contains non-PIC inline assembly code. This commit converts
lib/x86/usermode.c and x86/emulator.c to PIC, so x86/emulator.c can
compile and run in UEFI.

- x86/vmware_backdoors.c: it depends on lib/x86/usermode.c and now works
without modifications

- x86/eventinj.c

- x86/smap.c

- x86/access.c

- x86/umip.c

Signed-off-by: Zixuan Wang <zixuanwang@google.com>
---
 lib/x86/usermode.c  |  3 ++-
 x86/Makefile.common | 10 +++++-----
 x86/Makefile.x86_64 |  7 ++++---
 x86/access.c        |  9 +++++----
 x86/cet.c           |  8 +++++---
 x86/emulator.c      |  5 +++--
 x86/eventinj.c      |  6 ++++--
 x86/smap.c          |  8 ++++----
 x86/umip.c          | 10 +++++++---
 9 files changed, 39 insertions(+), 27 deletions(-)

Comments

Paolo Bonzini Oct. 21, 2021, 2:12 p.m. UTC | #1
On 04/10/21 22:49, Zixuan Wang wrote:
> From: Zixuan Wang <zixuanwang@google.com>
> 
> UEFI loads EFI applications to dynamic runtime addresses, so it requires
> all applications to be compiled as PIC (position independent code). PIC
> does not allow the usage of compile time absolute address.
> 
> This commit converts multiple x86 test cases to PIC so they can compile
> and run in UEFI:
> 
> - x86/cet.efi
> 
> - x86/emulator.c: x86/emulator.c depends on lib/x86/usermode.c. But
> usermode.c contains non-PIC inline assembly code. This commit converts
> lib/x86/usermode.c and x86/emulator.c to PIC, so x86/emulator.c can
> compile and run in UEFI.
> 
> - x86/vmware_backdoors.c: it depends on lib/x86/usermode.c and now works
> without modifications
> 
> - x86/eventinj.c
> 
> - x86/smap.c
> 
> - x86/access.c
> 
> - x86/umip.c
> 
> Signed-off-by: Zixuan Wang <zixuanwang@google.com>
> ---
>   lib/x86/usermode.c  |  3 ++-
>   x86/Makefile.common | 10 +++++-----
>   x86/Makefile.x86_64 |  7 ++++---
>   x86/access.c        |  9 +++++----
>   x86/cet.c           |  8 +++++---
>   x86/emulator.c      |  5 +++--
>   x86/eventinj.c      |  6 ++++--
>   x86/smap.c          |  8 ++++----
>   x86/umip.c          | 10 +++++++---
>   9 files changed, 39 insertions(+), 27 deletions(-)
> 
> diff --git a/lib/x86/usermode.c b/lib/x86/usermode.c
> index f032523..c550545 100644
> --- a/lib/x86/usermode.c
> +++ b/lib/x86/usermode.c
> @@ -58,7 +58,8 @@ uint64_t run_in_user(usermode_func func, unsigned int fault_vector,
>   			"pushq %[user_stack_top]\n\t"
>   			"pushfq\n\t"
>   			"pushq %[user_cs]\n\t"
> -			"pushq $user_mode\n\t"
> +			"lea user_mode(%%rip), %%rdx\n\t"
> +			"pushq %%rdx\n\t"
>   			"iretq\n"
>   
>   			"user_mode:\n\t"
> diff --git a/x86/Makefile.common b/x86/Makefile.common
> index 4859bf3..959379c 100644
> --- a/x86/Makefile.common
> +++ b/x86/Makefile.common
> @@ -81,16 +81,16 @@ tests-common = $(TEST_DIR)/vmexit.$(exe) $(TEST_DIR)/tsc.$(exe) \
>                  $(TEST_DIR)/init.$(exe) \
>                  $(TEST_DIR)/hyperv_synic.$(exe) $(TEST_DIR)/hyperv_stimer.$(exe) \
>                  $(TEST_DIR)/hyperv_connections.$(exe) \
> -               $(TEST_DIR)/tsx-ctrl.$(exe)
> +               $(TEST_DIR)/tsx-ctrl.$(exe) \
> +	       $(TEST_DIR)/eventinj.$(exe) \
> +               $(TEST_DIR)/umip.$(exe)
>   
>   # The following test cases are disabled when building EFI tests because they
>   # use absolute addresses in their inline assembly code, which cannot compile
>   # with the '-fPIC' flag
>   ifneq ($(TARGET_EFI),y)
> -tests-common += $(TEST_DIR)/eventinj.$(exe) \
> -                $(TEST_DIR)/smap.$(exe) \
> -                $(TEST_DIR)/realmode.$(exe) \
> -                $(TEST_DIR)/umip.$(exe)
> +tests-common += $(TEST_DIR)/smap.$(exe) \
> +                $(TEST_DIR)/realmode.$(exe)
>   endif
>   
>   test_cases: $(tests-common) $(tests)
> diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64
> index aa23b22..7e8a57a 100644
> --- a/x86/Makefile.x86_64
> +++ b/x86/Makefile.x86_64
> @@ -30,20 +30,21 @@ tests += $(TEST_DIR)/intel-iommu.$(exe)
>   tests += $(TEST_DIR)/rdpru.$(exe)
>   tests += $(TEST_DIR)/pks.$(exe)
>   tests += $(TEST_DIR)/pmu_lbr.$(exe)
> +tests += $(TEST_DIR)/emulator.$(exe)
> +tests += $(TEST_DIR)/vmware_backdoors.$(exe)
>   
>   # The following test cases are disabled when building EFI tests because they
>   # use absolute addresses in their inline assembly code, which cannot compile
>   # with the '-fPIC' flag
>   ifneq ($(TARGET_EFI),y)
>   tests += $(TEST_DIR)/access.$(exe)
> -tests += $(TEST_DIR)/emulator.$(exe)
>   tests += $(TEST_DIR)/svm.$(exe)
>   tests += $(TEST_DIR)/vmx.$(exe)
> -tests += $(TEST_DIR)/vmware_backdoors.$(exe)
> +endif
> +
>   ifneq ($(fcf_protection_full),)
>   tests += $(TEST_DIR)/cet.$(exe)
>   endif
> -endif
>   
>   include $(SRCDIR)/$(TEST_DIR)/Makefile.common
>   
> diff --git a/x86/access.c b/x86/access.c
> index 4725bbd..8d620a7 100644
> --- a/x86/access.c
> +++ b/x86/access.c
> @@ -700,7 +700,7 @@ static int ac_test_do_access(ac_test_t *at)
>   
>       if (F(AC_ACCESS_TWICE)) {
>   	asm volatile (
> -	    "mov $fixed2, %%rsi \n\t"
> +	    "lea fixed2(%%rip), %%rsi \n\t"
>   	    "mov (%[addr]), %[reg] \n\t"
>   	    "fixed2:"
>   	    : [reg]"=r"(r), [fault]"=a"(fault), "=b"(e)
> @@ -710,7 +710,7 @@ static int ac_test_do_access(ac_test_t *at)
>   	fault = 0;
>       }
>   
> -    asm volatile ("mov $fixed1, %%rsi \n\t"
> +    asm volatile ("lea fixed1(%%rip), %%rsi \n\t"
>   		  "mov %%rsp, %%rdx \n\t"
>   		  "cmp $0, %[user] \n\t"
>   		  "jz do_access \n\t"
> @@ -719,7 +719,8 @@ static int ac_test_do_access(ac_test_t *at)
>   		  "pushq %[user_stack_top] \n\t"
>   		  "pushfq \n\t"
>   		  "pushq %[user_cs] \n\t"
> -		  "pushq $do_access \n\t"
> +		  "lea do_access(%%rip), %%r8\n\t"
> +		  "pushq %%r8\n\t"
>   		  "iretq \n"
>   		  "do_access: \n\t"
>   		  "cmp $0, %[fetch] \n\t"
> @@ -744,7 +745,7 @@ static int ac_test_do_access(ac_test_t *at)
>   		    [user_cs]"i"(USER_CS),
>   		    [user_stack_top]"r"(user_stack + sizeof user_stack),
>   		    [kernel_entry_vector]"i"(0x20)
> -		  : "rsi");
> +		  : "rsi", "r8");
>   
>       asm volatile (".section .text.pf \n\t"
>   		  "page_fault: \n\t"
> diff --git a/x86/cet.c b/x86/cet.c
> index a21577a..a4b79cb 100644
> --- a/x86/cet.c
> +++ b/x86/cet.c
> @@ -52,7 +52,7 @@ static u64 cet_ibt_func(void)
>   	printf("No endbr64 instruction at jmp target, this triggers #CP...\n");
>   	asm volatile ("movq $2, %rcx\n"
>   		      "dec %rcx\n"
> -		      "leaq 2f, %rax\n"
> +		      "leaq 2f(%rip), %rax\n"
>   		      "jmp *%rax \n"
>   		      "2:\n"
>   		      "dec %rcx\n");
> @@ -67,7 +67,8 @@ void test_func(void) {
>   			"pushq %[user_stack_top]\n\t"
>   			"pushfq\n\t"
>   			"pushq %[user_cs]\n\t"
> -			"pushq $user_mode\n\t"
> +			"lea user_mode(%%rip), %%rax\n\t"
> +			"pushq %%rax\n\t"
>   			"iretq\n"
>   
>   			"user_mode:\n\t"
> @@ -77,7 +78,8 @@ void test_func(void) {
>   			[user_ds]"i"(USER_DS),
>   			[user_cs]"i"(USER_CS),
>   			[user_stack_top]"r"(user_stack +
> -					sizeof(user_stack)));
> +					sizeof(user_stack))
> +			: "rax");
>   }
>   
>   #define SAVE_REGS() \
> diff --git a/x86/emulator.c b/x86/emulator.c
> index 9fda1a0..4d2de24 100644
> --- a/x86/emulator.c
> +++ b/x86/emulator.c
> @@ -262,12 +262,13 @@ static void test_pop(void *mem)
>   
>   	asm volatile("mov %%rsp, %[tmp] \n\t"
>   		     "mov %[stack_top], %%rsp \n\t"
> -		     "push $1f \n\t"
> +		     "lea 1f(%%rip), %%rax \n\t"
> +		     "push %%rax \n\t"
>   		     "ret \n\t"
>   		     "2: jmp 2b \n\t"
>   		     "1: mov %[tmp], %%rsp"
>   		     : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top)
> -		     : "memory");
> +		     : "memory", "rax");
>   	report(1, "ret");
>   
>   	stack_top[-1] = 0x778899;
> diff --git a/x86/eventinj.c b/x86/eventinj.c
> index 46593c9..0cd68e8 100644
> --- a/x86/eventinj.c
> +++ b/x86/eventinj.c
> @@ -155,9 +155,11 @@ asm("do_iret:"
>   	"pushf"W" \n\t"
>   	"mov %cs, %ecx \n\t"
>   	"push"W" %"R "cx \n\t"
> -	"push"W" $2f \n\t"
> +	"lea"W" 2f(%"R "ip), %"R "bx \n\t"
> +	"push"W" %"R "bx \n\t"
>   
> -	"cmpb $0, no_test_device\n\t"	// see if need to flush
> +	"mov no_test_device(%"R "ip), %bl \n\t"
> +	"cmpb $0, %bl\n\t"		// see if need to flush
>   	"jnz 1f\n\t"
>   	"outl %eax, $0xe4 \n\t"		// flush page
>   	"1: \n\t"
> diff --git a/x86/smap.c b/x86/smap.c
> index ac2c8d5..b3ee16f 100644
> --- a/x86/smap.c
> +++ b/x86/smap.c
> @@ -161,10 +161,10 @@ int main(int ac, char **av)
>   		test = -1;
>   		asm("or $(" xstr(USER_BASE) "), %"R "sp \n"
>   		    "push $44 \n "
> -		    "decl test\n"
> +		    "decl test(%"R "ip)\n"
>   		    "and $~(" xstr(USER_BASE) "), %"R "sp \n"
>   		    "pop %"R "ax\n"
> -		    "movl %eax, test");
> +		    "movl %eax, test(%"R "ip)");
>   		report(pf_count == 0 && test == 44,
>   		       "write to user stack with AC=1");
>   
> @@ -173,10 +173,10 @@ int main(int ac, char **av)
>   		test = -1;
>   		asm("or $(" xstr(USER_BASE) "), %"R "sp \n"
>   		    "push $45 \n "
> -		    "decl test\n"
> +		    "decl test(%"R "ip)\n"
>   		    "and $~(" xstr(USER_BASE) "), %"R "sp \n"
>   		    "pop %"R "ax\n"
> -		    "movl %eax, test");
> +		    "movl %eax, test(%"R "ip)");
>   		report(pf_count == 1 && test == 45 && save == -1,
>   		       "write to user stack with AC=0");
>   
> diff --git a/x86/umip.c b/x86/umip.c
> index c5700b3..8b4e798 100644
> --- a/x86/umip.c
> +++ b/x86/umip.c
> @@ -23,7 +23,10 @@ static void gp_handler(struct ex_regs *regs)
>   
>   #define GP_ASM(stmt, in, clobber)                  \
>       asm volatile (                                 \
> -          "mov" W " $1f, %[expected_rip]\n\t"      \
> +          "push" W " %%" R "ax\n\t"                \
> +	  "lea 1f(%%" R "ip), %%" R "ax\n\t"       \
> +          "mov %%" R "ax, %[expected_rip]\n\t"     \
> +          "pop" W " %%" R "ax\n\t"                 \
>             "movl $2f-1f, %[skip_count]\n\t"         \
>             "1: " stmt "\n\t"                        \
>             "2: "                                    \
> @@ -130,7 +133,8 @@ static int do_ring3(void (*fn)(const char *), const char *arg)
>   		  "push" W " %%" R "dx \n\t"
>   		  "pushf" W "\n\t"
>   		  "push" W " %[user_cs] \n\t"
> -		  "push" W " $1f \n\t"
> +		  "lea 1f(%%" R "ip), %%" R "dx \n\t"
> +		  "push" W " %%" R "dx \n\t"
>   		  "iret" W "\n"
>   		  "1: \n\t"
>   		  "push %%" R "cx\n\t"   /* save kernel SP */
> @@ -144,7 +148,7 @@ static int do_ring3(void (*fn)(const char *), const char *arg)
>   #endif
>   
>   		  "pop %%" R "cx\n\t"
> -		  "mov $1f, %%" R "dx\n\t"
> +		  "lea 1f(%%" R "ip), %%" R "dx\n\t"
>   		  "int %[kernel_entry_vector]\n\t"
>   		  ".section .text.entry \n\t"
>   		  "kernel_entry: \n\t"
> 

I have left this patch out for now, because it breaks 32-bit builds. 
It's not a huge deal and can be redone on top of the rest.

Paolo
Zixuan Wang Oct. 26, 2021, 6:26 a.m. UTC | #2
On Thu, Oct 21, 2021 at 7:12 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> On 04/10/21 22:49, Zixuan Wang wrote:
> > From: Zixuan Wang <zixuanwang@google.com>
> >
> > UEFI loads EFI applications to dynamic runtime addresses, so it requires
> > all applications to be compiled as PIC (position independent code). PIC
> > does not allow the usage of compile time absolute address.
> >
> > This commit converts multiple x86 test cases to PIC so they can compile
> > and run in UEFI:
> >
> > - x86/cet.efi
> >
> > - x86/emulator.c: x86/emulator.c depends on lib/x86/usermode.c. But
> > usermode.c contains non-PIC inline assembly code. This commit converts
> > lib/x86/usermode.c and x86/emulator.c to PIC, so x86/emulator.c can
> > compile and run in UEFI.
> >
> > - x86/vmware_backdoors.c: it depends on lib/x86/usermode.c and now works
> > without modifications
> >
> > - x86/eventinj.c
> >
> > - x86/smap.c
> >
> > - x86/access.c
> >
> > - x86/umip.c
> >
> > Signed-off-by: Zixuan Wang <zixuanwang@google.com>
>
> I have left this patch out for now, because it breaks 32-bit builds.
> It's not a huge deal and can be redone on top of the rest.
>
> Paolo
>

Marc and I are working on a follow-up patch set that includes the
fixes for this patch under 32-bit mode. I have also identified a
potential bug in x86/umip.c and fixed it in the next patch set. The
full debugging detail is described in our off-list GitHub discussion
[1].

In summary, in the following line, %[sp0] can be compiled as a
%r8-based offset address:

x86/umip.c:127
"mov %%" R "sp, %[sp0]\n\t" /* kernel sp for exception handlers */

%r8 is then modified in the function call without saving/restoring,
thus making the following line using the wrong address.

x86/umip.c:148
"mov %[sp0], %%" R "sp\n\t"

This register is selected by the compiler, it's not guaranteed to be
%r8 so we cannot just push/pop %r8 before/after the function call. A
simple fix is to save the %rsp to %rbx (in addition to saving it to
%[sp0]). %rbx is a callee-saved register, so its value is not
modified.

We already have this fix in the patch set draft [1] and will post it once ready.

[1] https://github.com/marc-orr/KVM-Unit-Tests-dev-fork/pull/9

Best regards,
Zixuan
diff mbox series

Patch

diff --git a/lib/x86/usermode.c b/lib/x86/usermode.c
index f032523..c550545 100644
--- a/lib/x86/usermode.c
+++ b/lib/x86/usermode.c
@@ -58,7 +58,8 @@  uint64_t run_in_user(usermode_func func, unsigned int fault_vector,
 			"pushq %[user_stack_top]\n\t"
 			"pushfq\n\t"
 			"pushq %[user_cs]\n\t"
-			"pushq $user_mode\n\t"
+			"lea user_mode(%%rip), %%rdx\n\t"
+			"pushq %%rdx\n\t"
 			"iretq\n"
 
 			"user_mode:\n\t"
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 4859bf3..959379c 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -81,16 +81,16 @@  tests-common = $(TEST_DIR)/vmexit.$(exe) $(TEST_DIR)/tsc.$(exe) \
                $(TEST_DIR)/init.$(exe) \
                $(TEST_DIR)/hyperv_synic.$(exe) $(TEST_DIR)/hyperv_stimer.$(exe) \
                $(TEST_DIR)/hyperv_connections.$(exe) \
-               $(TEST_DIR)/tsx-ctrl.$(exe)
+               $(TEST_DIR)/tsx-ctrl.$(exe) \
+	       $(TEST_DIR)/eventinj.$(exe) \
+               $(TEST_DIR)/umip.$(exe)
 
 # The following test cases are disabled when building EFI tests because they
 # use absolute addresses in their inline assembly code, which cannot compile
 # with the '-fPIC' flag
 ifneq ($(TARGET_EFI),y)
-tests-common += $(TEST_DIR)/eventinj.$(exe) \
-                $(TEST_DIR)/smap.$(exe) \
-                $(TEST_DIR)/realmode.$(exe) \
-                $(TEST_DIR)/umip.$(exe)
+tests-common += $(TEST_DIR)/smap.$(exe) \
+                $(TEST_DIR)/realmode.$(exe)
 endif
 
 test_cases: $(tests-common) $(tests)
diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64
index aa23b22..7e8a57a 100644
--- a/x86/Makefile.x86_64
+++ b/x86/Makefile.x86_64
@@ -30,20 +30,21 @@  tests += $(TEST_DIR)/intel-iommu.$(exe)
 tests += $(TEST_DIR)/rdpru.$(exe)
 tests += $(TEST_DIR)/pks.$(exe)
 tests += $(TEST_DIR)/pmu_lbr.$(exe)
+tests += $(TEST_DIR)/emulator.$(exe)
+tests += $(TEST_DIR)/vmware_backdoors.$(exe)
 
 # The following test cases are disabled when building EFI tests because they
 # use absolute addresses in their inline assembly code, which cannot compile
 # with the '-fPIC' flag
 ifneq ($(TARGET_EFI),y)
 tests += $(TEST_DIR)/access.$(exe)
-tests += $(TEST_DIR)/emulator.$(exe)
 tests += $(TEST_DIR)/svm.$(exe)
 tests += $(TEST_DIR)/vmx.$(exe)
-tests += $(TEST_DIR)/vmware_backdoors.$(exe)
+endif
+
 ifneq ($(fcf_protection_full),)
 tests += $(TEST_DIR)/cet.$(exe)
 endif
-endif
 
 include $(SRCDIR)/$(TEST_DIR)/Makefile.common
 
diff --git a/x86/access.c b/x86/access.c
index 4725bbd..8d620a7 100644
--- a/x86/access.c
+++ b/x86/access.c
@@ -700,7 +700,7 @@  static int ac_test_do_access(ac_test_t *at)
 
     if (F(AC_ACCESS_TWICE)) {
 	asm volatile (
-	    "mov $fixed2, %%rsi \n\t"
+	    "lea fixed2(%%rip), %%rsi \n\t"
 	    "mov (%[addr]), %[reg] \n\t"
 	    "fixed2:"
 	    : [reg]"=r"(r), [fault]"=a"(fault), "=b"(e)
@@ -710,7 +710,7 @@  static int ac_test_do_access(ac_test_t *at)
 	fault = 0;
     }
 
-    asm volatile ("mov $fixed1, %%rsi \n\t"
+    asm volatile ("lea fixed1(%%rip), %%rsi \n\t"
 		  "mov %%rsp, %%rdx \n\t"
 		  "cmp $0, %[user] \n\t"
 		  "jz do_access \n\t"
@@ -719,7 +719,8 @@  static int ac_test_do_access(ac_test_t *at)
 		  "pushq %[user_stack_top] \n\t"
 		  "pushfq \n\t"
 		  "pushq %[user_cs] \n\t"
-		  "pushq $do_access \n\t"
+		  "lea do_access(%%rip), %%r8\n\t"
+		  "pushq %%r8\n\t"
 		  "iretq \n"
 		  "do_access: \n\t"
 		  "cmp $0, %[fetch] \n\t"
@@ -744,7 +745,7 @@  static int ac_test_do_access(ac_test_t *at)
 		    [user_cs]"i"(USER_CS),
 		    [user_stack_top]"r"(user_stack + sizeof user_stack),
 		    [kernel_entry_vector]"i"(0x20)
-		  : "rsi");
+		  : "rsi", "r8");
 
     asm volatile (".section .text.pf \n\t"
 		  "page_fault: \n\t"
diff --git a/x86/cet.c b/x86/cet.c
index a21577a..a4b79cb 100644
--- a/x86/cet.c
+++ b/x86/cet.c
@@ -52,7 +52,7 @@  static u64 cet_ibt_func(void)
 	printf("No endbr64 instruction at jmp target, this triggers #CP...\n");
 	asm volatile ("movq $2, %rcx\n"
 		      "dec %rcx\n"
-		      "leaq 2f, %rax\n"
+		      "leaq 2f(%rip), %rax\n"
 		      "jmp *%rax \n"
 		      "2:\n"
 		      "dec %rcx\n");
@@ -67,7 +67,8 @@  void test_func(void) {
 			"pushq %[user_stack_top]\n\t"
 			"pushfq\n\t"
 			"pushq %[user_cs]\n\t"
-			"pushq $user_mode\n\t"
+			"lea user_mode(%%rip), %%rax\n\t"
+			"pushq %%rax\n\t"
 			"iretq\n"
 
 			"user_mode:\n\t"
@@ -77,7 +78,8 @@  void test_func(void) {
 			[user_ds]"i"(USER_DS),
 			[user_cs]"i"(USER_CS),
 			[user_stack_top]"r"(user_stack +
-					sizeof(user_stack)));
+					sizeof(user_stack))
+			: "rax");
 }
 
 #define SAVE_REGS() \
diff --git a/x86/emulator.c b/x86/emulator.c
index 9fda1a0..4d2de24 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -262,12 +262,13 @@  static void test_pop(void *mem)
 
 	asm volatile("mov %%rsp, %[tmp] \n\t"
 		     "mov %[stack_top], %%rsp \n\t"
-		     "push $1f \n\t"
+		     "lea 1f(%%rip), %%rax \n\t"
+		     "push %%rax \n\t"
 		     "ret \n\t"
 		     "2: jmp 2b \n\t"
 		     "1: mov %[tmp], %%rsp"
 		     : [tmp]"=&r"(tmp) : [stack_top]"r"(stack_top)
-		     : "memory");
+		     : "memory", "rax");
 	report(1, "ret");
 
 	stack_top[-1] = 0x778899;
diff --git a/x86/eventinj.c b/x86/eventinj.c
index 46593c9..0cd68e8 100644
--- a/x86/eventinj.c
+++ b/x86/eventinj.c
@@ -155,9 +155,11 @@  asm("do_iret:"
 	"pushf"W" \n\t"
 	"mov %cs, %ecx \n\t"
 	"push"W" %"R "cx \n\t"
-	"push"W" $2f \n\t"
+	"lea"W" 2f(%"R "ip), %"R "bx \n\t"
+	"push"W" %"R "bx \n\t"
 
-	"cmpb $0, no_test_device\n\t"	// see if need to flush
+	"mov no_test_device(%"R "ip), %bl \n\t"
+	"cmpb $0, %bl\n\t"		// see if need to flush
 	"jnz 1f\n\t"
 	"outl %eax, $0xe4 \n\t"		// flush page
 	"1: \n\t"
diff --git a/x86/smap.c b/x86/smap.c
index ac2c8d5..b3ee16f 100644
--- a/x86/smap.c
+++ b/x86/smap.c
@@ -161,10 +161,10 @@  int main(int ac, char **av)
 		test = -1;
 		asm("or $(" xstr(USER_BASE) "), %"R "sp \n"
 		    "push $44 \n "
-		    "decl test\n"
+		    "decl test(%"R "ip)\n"
 		    "and $~(" xstr(USER_BASE) "), %"R "sp \n"
 		    "pop %"R "ax\n"
-		    "movl %eax, test");
+		    "movl %eax, test(%"R "ip)");
 		report(pf_count == 0 && test == 44,
 		       "write to user stack with AC=1");
 
@@ -173,10 +173,10 @@  int main(int ac, char **av)
 		test = -1;
 		asm("or $(" xstr(USER_BASE) "), %"R "sp \n"
 		    "push $45 \n "
-		    "decl test\n"
+		    "decl test(%"R "ip)\n"
 		    "and $~(" xstr(USER_BASE) "), %"R "sp \n"
 		    "pop %"R "ax\n"
-		    "movl %eax, test");
+		    "movl %eax, test(%"R "ip)");
 		report(pf_count == 1 && test == 45 && save == -1,
 		       "write to user stack with AC=0");
 
diff --git a/x86/umip.c b/x86/umip.c
index c5700b3..8b4e798 100644
--- a/x86/umip.c
+++ b/x86/umip.c
@@ -23,7 +23,10 @@  static void gp_handler(struct ex_regs *regs)
 
 #define GP_ASM(stmt, in, clobber)                  \
     asm volatile (                                 \
-          "mov" W " $1f, %[expected_rip]\n\t"      \
+          "push" W " %%" R "ax\n\t"                \
+	  "lea 1f(%%" R "ip), %%" R "ax\n\t"       \
+          "mov %%" R "ax, %[expected_rip]\n\t"     \
+          "pop" W " %%" R "ax\n\t"                 \
           "movl $2f-1f, %[skip_count]\n\t"         \
           "1: " stmt "\n\t"                        \
           "2: "                                    \
@@ -130,7 +133,8 @@  static int do_ring3(void (*fn)(const char *), const char *arg)
 		  "push" W " %%" R "dx \n\t"
 		  "pushf" W "\n\t"
 		  "push" W " %[user_cs] \n\t"
-		  "push" W " $1f \n\t"
+		  "lea 1f(%%" R "ip), %%" R "dx \n\t"
+		  "push" W " %%" R "dx \n\t"
 		  "iret" W "\n"
 		  "1: \n\t"
 		  "push %%" R "cx\n\t"   /* save kernel SP */
@@ -144,7 +148,7 @@  static int do_ring3(void (*fn)(const char *), const char *arg)
 #endif
 
 		  "pop %%" R "cx\n\t"
-		  "mov $1f, %%" R "dx\n\t"
+		  "lea 1f(%%" R "ip), %%" R "dx\n\t"
 		  "int %[kernel_entry_vector]\n\t"
 		  ".section .text.entry \n\t"
 		  "kernel_entry: \n\t"