Author: Armin Rigo <ar...@tunes.org> Branch: stmgc-c7 Changeset: r70266:31386d1544cb Date: 2014-03-24 21:47 +0100 http://bitbucket.org/pypy/pypy/changeset/31386d1544cb/
Log: Fix diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -157,8 +157,12 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: - self._load_shadowstack_top_in_ebx(mc, gcrootmap) + mc.MOV(ebx, self.heap_shadowstack_top()) mc.MOV_mr((self.SEGMENT_NO, ebx.value, -WORD), eax.value) + # STM note: this stores the updated jitframe object in the + # position -WORD, but (in this case) leaves the position + # -2*WORD untouched. This old jitframe object remains in + # the shadowstack just in case we do an abort later. mc.MOV_bi((self.SEGMENT_FRAME, gcmap_ofs), 0) self._pop_all_regs_from_frame(mc, [], self.cpu.supports_floats) @@ -771,7 +775,7 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap and gcrootmap.is_shadow_stack: - self._call_header_shadowstack(gcrootmap) + self._call_header_shadowstack() def _call_header_with_stack_check(self): self._call_header() @@ -801,13 +805,9 @@ # we called a pypy_stm_start_transaction() earlier. assert IS_X86_64 # - # load the shadowstack pointer into ebx, and decrement it, - # but don't decrement the official shadowstack yet! We just - # keep it in ebx for a while (a callee-saved register). + # load the shadowstack pointer into ebx (a callee-saved register) mc = self.mc - rst = self.heap_tl(gcrootmap.get_root_stack_top_addr()) - mc.MOV(ebx, rst) - mc.SUB_ri(ebx.value, WORD) + mc.MOV(ebx, self.heap_shadowstack_top()) # load the address of the jmpbuf mc.LEA_rs(edi.value, STM_JMPBUF_OFS) # compare it with the currently-stored jmpbuf @@ -821,18 +821,20 @@ mc.CALL(imm(rstm.adr__stm_become_inevitable)) # there could have been a collection in _stm_become_inevitable; # reload the frame into ebp - mc.MOV_rm(ebp.value, (self.SEGMENT_NO, ebx.value, 0)) + mc.MOV_rm(ebp.value, (self.SEGMENT_NO, ebx.value, -WORD)) # # this is where the JNE above jumps offset = mc.get_relative_pos() - jne_location assert 0 < offset <= 127 mc.overwrite(jne_location-1, chr(offset)) # - # now store ebx back, which will really decrement the shadowstack - mc.MOV(rst, ebx) + # now decrement ebx by 2*WORD and store it back, which will + # really decrement the shadowstack + mc.SUB_ri(ebx.value, 2 * WORD) + mc.MOV(self.heap_shadowstack_top(), ebx) elif gcrootmap and gcrootmap.is_shadow_stack: - self._call_footer_shadowstack(gcrootmap) + self._call_footer_shadowstack() # the return value is the jitframe self.mc.MOV_rr(eax.value, ebp.value) @@ -845,26 +847,37 @@ self.mc.ADD_ri(esp.value, self._get_whole_frame_size() * WORD) self.mc.RET() - def _load_shadowstack_top_in_ebx(self, mc, gcrootmap): - """Loads the shadowstack top in ebx, and returns an integer - that gives the address of the stack top. - """ - mc.MOV(ebx, self.heap_tl(gcrootmap.get_root_stack_top_addr())) + def heap_shadowstack_top(self): + """Return an AddressLoc for '&shadowstack', the shadow stack top.""" + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + return self.heap_tl(gcrootmap.get_root_stack_top_addr()) - def _call_header_shadowstack(self, gcrootmap): + def _call_header_shadowstack(self): # put the frame in ebp on the shadowstack for the GC to find # (ebp is a writeable object and does not need a write-barrier # again (ensured by the code calling the loop)) - self._load_shadowstack_top_in_ebx(self.mc, gcrootmap) + self.mc.MOV(ebx, self.heap_shadowstack_top()) self.mc.MOV_mr((self.SEGMENT_NO, ebx.value, 0), ebp.value) # MOV [ebx], ebp - self.mc.ADD_ri(ebx.value, WORD) - self.mc.MOV(self.heap_tl(gcrootmap.get_root_stack_top_addr()), ebx) - # MOV [rootstacktop], ebx + if self.cpu.gc_ll_descr.stm: + # With stm, we push the jitframe twice on the shadowstack. + # If we break transaction inside this frame, we'll do it + # with only one item on the shadowstack, and then we'll + # duplicate it again. The point is to store both the + # old and the new copy when case we do a realloc_frame, + # just for the case where we later abort. + self.mc.MOV_mr((self.SEGMENT_NO, ebx.value, WORD), ebp.value) + self.mc.ADD_ri(ebx.value, 2 * WORD) + else: + self.mc.ADD_ri(ebx.value, WORD) + self.mc.MOV(self.heap_shadowstack_top(), ebx) # MOV [rootstacktop], ebx - def _call_footer_shadowstack(self, gcrootmap): - self.mc.SUB(self.heap_tl(gcrootmap.get_root_stack_top_addr()), WORD) - # SUB [rootstacktop], WORD + def _call_footer_shadowstack(self): + # SUB [rootstacktop], WORD (or 2 * WORD with STM) + if self.cpu.gc_ll_descr.stm: + self.mc.SUB(self.heap_shadowstack_top(), 2 * WORD) + else: + self.mc.SUB(self.heap_shadowstack_top(), WORD) def redirect_call_assembler(self, oldlooptoken, newlooptoken): # some minimal sanity checking @@ -1133,9 +1146,12 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: if gcrootmap.is_shadow_stack: - mc.MOV(ecx, self.heap_tl(gcrootmap.get_root_stack_top_addr())) + mc.MOV(ecx, self.heap_shadowstack_top()) mc.MOV(ebp, mem(self.SEGMENT_NO, ecx, -WORD)) - # + self._reload_frame_wb(mc, align_stack) + + def _reload_frame_wb(self, mc, align_stack=False): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap wbdescr = self.cpu.gc_ll_descr.write_barrier_descr if gcrootmap and wbdescr: # frame never uses card marking, so we enforce this is not @@ -2535,6 +2551,12 @@ # call stm_commit_transaction() mc.CALL(imm(rstm.adr_stm_commit_transaction)) # + # copy shadowstack[-1] into shadowstack[-2]: the latter is + # not going to be used any more, now that we committed + mc.MOV(ebx, self.heap_shadowstack_top()) + mc.MOV_rm(eax.value, (self.SEGMENT_NO, ebx, -WORD)) + mc.MOV_mr((self.SEGMENT_NO, ebx, -2 * WORD), eax.value) + # # update the two words in the STM_RESUME_BUF, as described # in arch.py. The "learip" pseudo-instruction turns into # what is, in gnu as syntax: lea 0(%rip), %rax (the 0 is @@ -2561,8 +2583,13 @@ mc.LEA_rs(esi.value, STM_JMPBUF_OFS_RBP) mc.CALL(imm(rstm.adr_pypy_stm_start_transaction)) # - # reload ebp with the frame now - self._reload_frame_if_necessary(self.mc) + # reload ebp with the frame now, picking the value from + # shadowstack[-2] and duplicating it into shadowstack[-1]. + # Only realloc_frame can make these values different again. + mc.MOV(ebx, self.heap_shadowstack_top()) + mc.MOV_rm(ebp.value, (self.SEGMENT_NO, ebx, -2 * WORD)) + mc.MOV_mr((self.SEGMENT_NO, ebx, -WORD), ebp.value) + self._reload_frame_wb(self.mc) # # restore regs self._push_pop_regs_to_frame(False, mc, grp_regs, xmm_regs) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit