[mupen64plus-core] 183/310: Don't store mapped host registers on stack before dynarec call

Sven Eckelmann ecsv-guest at moszumanska.debian.org
Thu Nov 26 05:57:56 UTC 2015


This is an automated email from the git hooks/post-receive script.

ecsv-guest pushed a commit to branch armhf_test
in repository mupen64plus-core.

commit 0557185dcb1ce450fc291d4e7d5b6f59b909c0e9
Author: Sven Eckelmann <sven at narfation.org>
Date:   Sun Sep 23 13:20:15 2012 +0200

    Don't store mapped host registers on stack before dynarec call
    
    The dynamic recompiler uses a simple register mapping for currently used
    registers to reduce memory access for operations. The content of these
    registers have to be saved back to the memory region containing the emulated
    register bar before they will be remapped or may get damaged by an unsave
    operation.
    
    Emulated operations in the amd64 dynamic recompiler tried to avoid the complex
    register free'ing operation before an call to a C function by storing the
    content of mapped registers to the stack. This implementation is faulty because
    
     * the return address (top most stack position when the dynamic recompiler
       started a recompiled block) may get written during the execution of the C
       function. The problem is that the return address is moved to another
       position when the registers were stored in the stack and therefore the
       content of a saved register gets damaged by this write.
     * the called C function may want to access the content of an emulated
       register. This is done by reading the content of the emulated register bar
       in memory. This read will return an outdated value because the new value is
       only stored in the stack.
    
    This problem can be avoided without more complicated checks by not saving the
    content on the stack and instead unmapping the registers and saving their
    content in the emulated register bar.
---
 debian/changelog                              |   3 +
 debian/patches/dynarec_amd64_nostackreg.patch | 222 ++++++++++++++++++++++++++
 debian/patches/series                         |   1 +
 3 files changed, 226 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index 482bf05..2ce211b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,9 @@
 mupen64plus-core (1.99.5+115+5afdc1c5e077-2) UNRELEASED; urgency=low
 
   * Upgraded to policy 3.9.4, no changes required
+  * debian/patches:
+    - Add dynarec_amd64_nostackreg.patch, Don't store mapped host registers on
+      stack before dynarec call
 
  -- Sven Eckelmann <sven at narfation.org>  Wed, 19 Sep 2012 08:49:52 +0200
 
diff --git a/debian/patches/dynarec_amd64_nostackreg.patch b/debian/patches/dynarec_amd64_nostackreg.patch
new file mode 100644
index 0000000..a41d422
--- /dev/null
+++ b/debian/patches/dynarec_amd64_nostackreg.patch
@@ -0,0 +1,222 @@
+Description: Don't store mapped host registers on stack before dynarec call
+ The dynamic recompiler uses a simple register mapping for currently used
+ registers to reduce memory access for operations. The content of these
+ registers have to be saved back to the memory region containing the emulated
+ register bar before they will be remapped or may get damaged by an unsave
+ operation.
+ .
+ Emulated operations in the amd64 dynamic recompiler tried to avoid the complex
+ register free'ing operation before an call to a C function by storing the
+ content of mapped registers to the stack. This implementation is faulty because
+ .
+  * the return address (top most stack position when the dynamic recompiler
+    started a recompiled block) may get written during the execution of the C
+    function. The problem is that the return address is moved to another
+    position when the registers were stored in the stack and therefore the
+    content of a saved register gets damaged by this write.
+  * the called C function may want to access the content of an emulated
+    register. This is done by reading the content of the emulated register bar
+    in memory. This read will return an outdated value because the new value is
+    only stored in the stack.
+ .
+ This problem can be avoided without more complicated checks by not saving the
+ content on the stack and instead unmapping the registers and saving their
+ content in the emulated register bar.
+Author: Sven Eckelmann <sven at narfation.org>
+
+---
+diff --git a/src/r4300/x86_64/assemble.h b/src/r4300/x86_64/assemble.h
+index 427b03d7cfda9d528268c2e646be3ae4ee51264c..2cdd72c6864402131c309c71f0f9f091a3b9a44b 100644
+--- a/src/r4300/x86_64/assemble.h
++++ b/src/r4300/x86_64/assemble.h
+@@ -326,16 +326,6 @@ static inline void setb_reg8(unsigned int reg8)
+    put8(0xC0 | reg8);
+ }
+ 
+-static inline void push_reg64(unsigned int reg64)
+-{
+-   put8(0x50 + reg64);
+-}
+-
+-static inline void pop_reg64(unsigned int reg64)
+-{
+-   put8(0x58 + reg64);
+-}
+-
+ static inline void test_m32rel_imm32(unsigned int *m32, unsigned int imm32)
+ {
+    int offset = rel_r15_offset(m32, "test_m32rel_imm32");
+diff --git a/src/r4300/x86_64/gr4300.c b/src/r4300/x86_64/gr4300.c
+index ccf73144f2fde6b10e700b677847ab649cbc2436..dca95e07c0c6709e1260b812002cb3672054fd62 100644
+--- a/src/r4300/x86_64/gr4300.c
++++ b/src/r4300/x86_64/gr4300.c
+@@ -1354,6 +1354,8 @@ void genlb(void)
+ #ifdef INTERPRET_LB
+    gencallinterp((unsigned long long)cached_interpreter_table.LB, 0);
+ #else
++   free_registers_move_start();
++
+    ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
+ 
+    mov_reg64_imm64(base1, (unsigned long long) readmemb);
+@@ -1379,9 +1381,7 @@ void genlb(void)
+    mov_m64rel_xreg64((unsigned long long *)(&rdword), gpr1);
+    shr_reg32_imm8(gpr2, 16);
+    mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
+-   stack_save_registers();
+    call_reg64(gpr2);
+-   stack_load_registers();
+    movsx_xreg32_m8rel(gpr1, (unsigned char *)dst->f.i.rt);
+    jmp_imm_short(24);
+ 
+@@ -1404,6 +1404,8 @@ void genlh(void)
+ #ifdef INTERPRET_LH
+    gencallinterp((unsigned long long)cached_interpreter_table.LH, 0);
+ #else
++   free_registers_move_start();
++
+    ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
+ 
+    mov_reg64_imm64(base1, (unsigned long long) readmemh);
+@@ -1429,9 +1431,7 @@ void genlh(void)
+    mov_m64rel_xreg64((unsigned long long *)(&rdword), gpr1);
+    shr_reg32_imm8(gpr2, 16);
+    mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
+-   stack_save_registers();
+    call_reg64(gpr2);
+-   stack_load_registers();
+    movsx_xreg32_m16rel(gpr1, (unsigned short *)dst->f.i.rt);
+    jmp_imm_short(24);
+ 
+@@ -1462,6 +1462,8 @@ void genlw(void)
+ #ifdef INTERPRET_LW
+    gencallinterp((unsigned long long)cached_interpreter_table.LW, 0);
+ #else
++   free_registers_move_start();
++
+    ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
+ 
+    mov_reg64_imm64(base1, (unsigned long long) readmem);
+@@ -1492,14 +1494,13 @@ void genlw(void)
+    mov_m64rel_xreg64((unsigned long long *)(&rdword), gpr1);
+    shr_reg32_imm8(gpr2, 16);
+    mov_reg64_preg64x8preg64(gpr1, gpr2, base1);
+-   stack_save_registers();
+    call_reg64(gpr1);
+-   stack_load_registers();
+    mov_xreg32_m32rel(gpr1, (unsigned int *)(dst->f.i.rt));
+ 
+    jump_end_rel8();
+ 
+    set_register_state(gpr1, (unsigned int*)dst->f.i.rt, 1, 0);     // set gpr1 state as dirty, and bound to r4300 reg RT
++
+ #endif
+ }
+ 
+@@ -1512,6 +1513,8 @@ void genlbu(void)
+ #ifdef INTERPRET_LBU
+    gencallinterp((unsigned long long)cached_interpreter_table.LBU, 0);
+ #else
++   free_registers_move_start();
++
+    ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
+ 
+    mov_reg64_imm64(base1, (unsigned long long) readmemb);
+@@ -1537,9 +1540,7 @@ void genlbu(void)
+    mov_m64rel_xreg64((unsigned long long *)(&rdword), gpr1);
+    shr_reg32_imm8(gpr2, 16);
+    mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
+-   stack_save_registers();
+    call_reg64(gpr2);
+-   stack_load_registers();
+    mov_xreg32_m32rel(gpr1, (unsigned int *)dst->f.i.rt);
+    jmp_imm_short(23);
+ 
+@@ -1563,6 +1564,8 @@ void genlhu(void)
+ #ifdef INTERPRET_LHU
+    gencallinterp((unsigned long long)cached_interpreter_table.LHU, 0);
+ #else
++   free_registers_move_start();
++
+    ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
+ 
+    mov_reg64_imm64(base1, (unsigned long long) readmemh);
+@@ -1588,9 +1591,7 @@ void genlhu(void)
+    mov_m64rel_xreg64((unsigned long long *)(&rdword), gpr1);
+    shr_reg32_imm8(gpr2, 16);
+    mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
+-   stack_save_registers();
+    call_reg64(gpr2);
+-   stack_load_registers();
+    mov_xreg32_m32rel(gpr1, (unsigned int *)dst->f.i.rt);
+    jmp_imm_short(23);
+ 
+@@ -1622,6 +1623,8 @@ void genlwu(void)
+ #ifdef INTERPRET_LWU
+    gencallinterp((unsigned long long)cached_interpreter_table.LWU, 0);
+ #else
++   free_registers_move_start();
++
+    ld_register_alloc(&gpr1, &gpr2, &base1, &base2);
+ 
+    mov_reg64_imm64(base1, (unsigned long long) readmem);
+@@ -1647,9 +1650,7 @@ void genlwu(void)
+    mov_m64rel_xreg64((unsigned long long *)(&rdword), gpr1);
+    shr_reg32_imm8(gpr2, 16);
+    mov_reg64_preg64x8preg64(gpr2, gpr2, base1);
+-   stack_save_registers();
+    call_reg64(gpr2);
+-   stack_load_registers();
+    mov_xreg32_m32rel(gpr1, (unsigned int *)dst->f.i.rt);
+    jmp_imm_short(19);
+ 
+diff --git a/src/r4300/x86_64/regcache.c b/src/r4300/x86_64/regcache.c
+index b4e8ef70edcd5a609800c63b140a2ed54f634bae..4a1aa41e2e5f92255add2e037e6be3a7d24b5a3a 100644
+--- a/src/r4300/x86_64/regcache.c
++++ b/src/r4300/x86_64/regcache.c
+@@ -152,32 +152,6 @@ void free_register(int reg)
+   free_since[reg] = dst+1;
+ }
+ 
+-void stack_save_registers(void)
+-{
+-  int i;
+-
+-  for (i=0; i<8; i++)
+-  {
+-    if (last_access[i])
+-    {
+-      push_reg64(i);
+-    }
+-  }
+-}
+-
+-void stack_load_registers(void)
+-{
+-  int i;
+-
+-  for (i=7; i>=0; i--)
+-  {
+-    if (last_access[i])
+-    {
+-      pop_reg64(i);
+-    }
+-  }
+-}
+-
+ int lru_register(void)
+ {
+    unsigned long oldest_access = 0xFFFFFFFFFFFFFFFFULL;
+diff --git a/src/r4300/x86_64/regcache.h b/src/r4300/x86_64/regcache.h
+index 0f83a9538b0738e0cdf30d61d0f9d920b4dfe691..0819f103ec027c428bcb5e3e4a0d17e8c13715f5 100644
+--- a/src/r4300/x86_64/regcache.h
++++ b/src/r4300/x86_64/regcache.h
+@@ -29,8 +29,6 @@ void init_cache(precomp_instr* start);
+ void free_registers_move_start(void);
+ void free_all_registers(void);
+ void free_register(int reg);
+-void stack_save_registers(void);
+-void stack_load_registers(void);
+ int is64(unsigned int *addr);
+ int lru_register(void);
+ int lru_base_register(void);
diff --git a/debian/patches/series b/debian/patches/series
index f2b4630..cca1f09 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
 dejavu-font.patch
 printf_fixup.patch
 disable_recompiler_disassembler.patch
+dynarec_amd64_nostackreg.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/mupen64plus-core.git



More information about the Pkg-games-commits mailing list