Example #1
0
 def write_real_errno(self, save_err):
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         # Just before a call, read '*_errno' and write it into the
         # real 'errno'.  The x0-x7 registers contain arguments to the
         # future call;
         # the x8-x10 registers contain various stuff. XXX what?
         # We still have x11 and up.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LDR_ri(r.x11.value, r.sp.value,
                        self.asm.saved_threadlocal_addr + self.current_sp)
         self.mc.LDR_ri(r.ip0.value, r.x11.value, p_errno)
         self.mc.LDR_ri(r.x11.value, r.x11.value, rpy_errno)
         self.mc.STR_ri(r.x11.value, r.ip0.value, 0)
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         # Same, but write zero.
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LDR_ri(r.x11.value, r.sp.value,
                        self.asm.saved_threadlocal_addr + self.current_sp)
         self.mc.LDR_ri(r.ip0.value, r.x11.value, p_errno)
         self.mc.MOVZ_r_u16(r.x11.value, 0, 0)
         self.mc.STR_ri(r.x11.value, r.ip0.value, 0)
Example #2
0
    def write_real_errno(self, save_err):
        """This occurs just before emit_raw_call().
        """
        mc = self.mc

        if handle_lasterror and (save_err & rffi.RFFI_READSAVED_LASTERROR):
            # must call SetLastError().  There are no registers to save
            # if we are on 32-bit in this case: no register contains
            # the arguments to the main function we want to call afterwards.
            # On win64, though, it's more messy.  It could be better optimized
            # but for now we save (again) the registers containing arguments,
            # and restore them afterwards.
            from rpython.rlib.rwin32 import _SetLastError
            adr = llmemory.cast_ptr_to_adr(_SetLastError)
            SetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
            #
            if save_err & rffi.RFFI_ALT_ERRNO:
                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
            else:
                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi or r12, callee-saved
            if not WIN64:
                self.save_stack_position()  # => edi, callee-saved
                mc.PUSH_m((tlofsreg.value, lasterror))
                mc.CALL(imm(follow_jump(SetLastError_addr)))
                # restore the stack position without assuming a particular
                # calling convention of _SetLastError()
                self.mc.stack_frame_size_delta(-WORD)
                self.mc.MOV(esp, self.saved_stack_position_reg)
            else:
                self.win64_save_register_args()
                mc.MOV_rm(ecx.value, (tlofsreg.value, lasterror))
                mc.CALL(imm(follow_jump(SetLastError_addr)))
                self.win64_restore_register_args()

        if save_err & rffi.RFFI_READSAVED_ERRNO:
            # Just before a call, read '*_errno' and write it into the
            # real 'errno'.  Most registers are free here, including the
            # callee-saved ones, except 'ebx' and except the ones used to
            # pass the arguments on x86-64.
            if save_err & rffi.RFFI_ALT_ERRNO:
                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
            else:
                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi or r12, callee-saved
            if IS_X86_32:
                tmpreg = edx
            else:
                tmpreg = r10  # edx is used for 3rd argument
            mc.MOV_rm(tmpreg.value, (tlofsreg.value, p_errno))
            mc.MOV32_rm(eax.value, (tlofsreg.value, rpy_errno))
            mc.MOV32_mr((tmpreg.value, 0), eax.value)
        elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
            # Same, but write zero.
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi or r12, callee-saved
            mc.MOV_rm(eax.value, (tlofsreg.value, p_errno))
            mc.MOV32_mi((eax.value, 0), 0)
Example #3
0
    def write_real_errno(self, save_err):
        """This occurs just before emit_raw_call().
        """
        mc = self.mc

        if handle_lasterror and (save_err & rffi.RFFI_READSAVED_LASTERROR):
            # must call SetLastError().  There are no registers to save
            # because we are on 32-bit in this case: no register contains
            # the arguments to the main function we want to call afterwards.
            from rpython.rlib.rwin32 import _SetLastError
            adr = llmemory.cast_ptr_to_adr(_SetLastError)
            SetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
            assert isinstance(self, CallBuilder32)    # Windows 32-bit only
            #
            if save_err & rffi.RFFI_ALT_ERRNO:
                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
            else:
                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()    # => esi, callee-saved
            self.save_stack_position()         # => edi, callee-saved
            mc.PUSH_m((tlofsreg.value, lasterror))
            mc.CALL(imm(follow_jump(SetLastError_addr)))
            # restore the stack position without assuming a particular
            # calling convention of _SetLastError()
            self.mc.stack_frame_size_delta(-WORD)
            self.mc.MOV(esp, self.saved_stack_position_reg)

        if save_err & rffi.RFFI_READSAVED_ERRNO:
            # Just before a call, read '*_errno' and write it into the
            # real 'errno'.  Most registers are free here, including the
            # callee-saved ones, except 'ebx' and except the ones used to
            # pass the arguments on x86-64.
            if save_err & rffi.RFFI_ALT_ERRNO:
                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
            else:
                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()    # => esi or r12, callee-saved
            if IS_X86_32:
                tmpreg = edx
            else:
                tmpreg = r11     # edx is used for 3rd argument
            mc.MOV_rm(tmpreg.value, (tlofsreg.value, p_errno))
            mc.MOV32_rm(eax.value, (tlofsreg.value, rpy_errno))
            mc.MOV32_mr((tmpreg.value, 0), eax.value)
        elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
            # Same, but write zero.
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()    # => esi or r12, callee-saved
            mc.MOV_rm(eax.value, (tlofsreg.value, p_errno))
            mc.MOV32_mi((eax.value, 0), 0)
Example #4
0
    def write_real_errno(self, save_err):
        """This occurs just before emit_raw_call().
        """
        mc = self.mc

        if handle_lasterror and (save_err & rffi.RFFI_READSAVED_LASTERROR):
            # must call SetLastError().  There are no registers to save
            # because we are on 32-bit in this case: no register contains
            # the arguments to the main function we want to call afterwards.
            from rpython.rlib.rwin32 import _SetLastError
            adr = llmemory.cast_ptr_to_adr(_SetLastError)
            SetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
            assert isinstance(self, CallBuilder32)  # Windows 32-bit only
            #
            if save_err & rffi.RFFI_ALT_ERRNO:
                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
            else:
                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi, callee-saved
            self.save_stack_position()  # => edi, callee-saved
            mc.PUSH_m((tlofsreg.value, lasterror))
            mc.CALL(imm(follow_jump(SetLastError_addr)))
            # restore the stack position without assuming a particular
            # calling convention of _SetLastError()
            self.mc.MOV(esp, self.saved_stack_position_reg)

        if save_err & rffi.RFFI_READSAVED_ERRNO:
            # Just before a call, read '*_errno' and write it into the
            # real 'errno'.  Most registers are free here, including the
            # callee-saved ones, except 'ebx' and except the ones used to
            # pass the arguments on x86-64.
            if save_err & rffi.RFFI_ALT_ERRNO:
                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
            else:
                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi or r12, callee-saved
            if IS_X86_32:
                tmpreg = edx
            else:
                tmpreg = r11  # edx is used for 3rd argument
            mc.MOV_rm(tmpreg.value, (tlofsreg.value, p_errno))
            mc.MOV32_rm(eax.value, (tlofsreg.value, rpy_errno))
            mc.MOV32_mr((tmpreg.value, 0), eax.value)
        elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
            # Same, but write zero.
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi or r12, callee-saved
            mc.MOV_rm(eax.value, (tlofsreg.value, p_errno))
            mc.MOV32_mi((eax.value, 0), 0)
Example #5
0
 def write_real_errno(self, save_err):
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         # Just before a call, read 'rpy_errno' and write it into the
         # real 'errno'.  The r0-r3 registers contain arguments to the
         # future call; the r5-r7 registers contain various stuff.
         # We still have r8-r12.
         rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LDR_ri(r.r9.value, r.sp.value,
                        self.asm.saved_threadlocal_addr + self.current_sp)
         self.mc.LDR_ri(r.ip.value, r.r9.value, p_errno)
         self.mc.LDR_ri(r.r9.value, r.r9.value, rpy_errno)
         self.mc.STR_ri(r.r9.value, r.ip.value)
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         # Same, but write zero.
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LDR_ri(r.r9.value, r.sp.value,
                        self.asm.saved_threadlocal_addr + self.current_sp)
         self.mc.LDR_ri(r.ip.value, r.r9.value, p_errno)
         self.mc.MOV_ri(r.r9.value, 0)
         self.mc.STR_ri(r.r9.value, r.ip.value)
Example #6
0
 def write_real_errno(self, save_err):
     # r11 is saved in call_releasegil_addr_and_move_real_arguments,
     # thus can be used freely here!
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         # Just before a call, read '*_errno' and write it into the
         # real 'errno'.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LG(r.r11, l.addr(THREADLOCAL_ADDR_OFFSET, r.SP))
         self.mc.LGF(r.SCRATCH2, l.addr(rpy_errno, r.r11))
         self.mc.LG(r.r11, l.addr(p_errno, r.r11))
         self.mc.STY(r.SCRATCH2, l.addr(0,r.r11))
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         # Same, but write zero.
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LG(r.r11, l.addr(THREADLOCAL_ADDR_OFFSET, r.SP))
         self.mc.LG(r.r11, l.addr(p_errno, r.r11))
         self.mc.LGHI(r.SCRATCH, l.imm(0))
         self.mc.STY(r.SCRATCH, l.addr(0,r.r11))
Example #7
0
 def write_real_errno(self, save_err):
     # r11 is saved in call_releasegil_addr_and_move_real_arguments,
     # thus can be used freely here!
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         # Just before a call, read '*_errno' and write it into the
         # real 'errno'.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LG(r.r11, l.addr(THREADLOCAL_ADDR_OFFSET, r.SP))
         self.mc.LGF(r.SCRATCH2, l.addr(rpy_errno, r.r11))
         self.mc.LG(r.r11, l.addr(p_errno, r.r11))
         self.mc.STY(r.SCRATCH2, l.addr(0, r.r11))
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         # Same, but write zero.
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LG(r.r11, l.addr(THREADLOCAL_ADDR_OFFSET, r.SP))
         self.mc.LG(r.r11, l.addr(p_errno, r.r11))
         self.mc.LGHI(r.SCRATCH, l.imm(0))
         self.mc.STY(r.SCRATCH, l.addr(0, r.r11))
Example #8
0
 def read_real_errno(self, save_err):
     if save_err & rffi.RFFI_SAVE_ERRNO:
         # Just after a call, read the real 'errno' and save a copy of
         # it inside our thread-local 'rpy_errno'.  Registers r8-r12
         # are unused here, and registers r2-r3 never contain anything
         # after the call.
         rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LDR_ri(r.r3.value, r.sp.value,
                        self.asm.saved_threadlocal_addr)
         self.mc.LDR_ri(r.ip.value, r.r3.value, p_errno)
         self.mc.LDR_ri(r.ip.value, r.ip.value, 0)
         self.mc.STR_ri(r.ip.value, r.r3.value, rpy_errno)
Example #9
0
 def read_real_errno(self, save_err):
     if save_err & rffi.RFFI_SAVE_ERRNO:
         # Just after a call, read the real 'errno' and save a copy of
         # it inside our thread-local '*_errno'.  Registers r4-r10
         # never contain anything after the call.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.ld(r.r9.value, r.SP.value, THREADLOCAL_ADDR_OFFSET)
         self.mc.ld(r.r10.value, r.r9.value, p_errno)
         self.mc.lwz(r.r10.value, r.r10.value, 0)
         self.mc.stw(r.r10.value, r.r9.value, rpy_errno)
Example #10
0
 def write_real_errno(self, save_err):
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         # Just before a call, read '*_errno' and write it into the
         # real 'errno'.  A lot of registers are free here, notably
         # r11 and r0.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.ld(r.r11.value, r.SP.value,
                    THREADLOCAL_ADDR_OFFSET + self.subtracted_to_sp)
         self.mc.lwz(r.r0.value, r.r11.value, rpy_errno)
         self.mc.ld(r.r11.value, r.r11.value, p_errno)
         self.mc.stw(r.r0.value, r.r11.value, 0)
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         # Same, but write zero.
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.ld(r.r11.value, r.SP.value,
                    THREADLOCAL_ADDR_OFFSET + self.subtracted_to_sp)
         self.mc.ld(r.r11.value, r.r11.value, p_errno)
         self.mc.li(r.r0.value, 0)
         self.mc.stw(r.r0.value, r.r11.value, 0)
Example #11
0
 def read_real_errno(self, save_err):
     if save_err & rffi.RFFI_SAVE_ERRNO:
         # Just after a call, read the real 'errno' and save a copy of
         # it inside our thread-local '*_errno'.  Registers r3-r6
         # never contain anything after the call.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LG(r.r3, l.addr(THREADLOCAL_ADDR_OFFSET, r.SP))
         self.mc.LG(r.r4, l.addr(p_errno, r.r3))
         self.mc.LGF(r.r4, l.addr(0, r.r4))
         self.mc.STY(r.r4, l.addr(rpy_errno, r.r3))
Example #12
0
 def read_real_errno(self, save_err):
     if save_err & rffi.RFFI_SAVE_ERRNO:
         # Just after a call, read the real 'errno' and save a copy of
         # it inside our thread-local '*_errno'.  Registers r3-r6
         # never contain anything after the call.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.LG(r.r3, l.addr(THREADLOCAL_ADDR_OFFSET, r.SP))
         self.mc.LG(r.r4, l.addr(p_errno, r.r3))
         self.mc.LGF(r.r4, l.addr(0, r.r4))
         self.mc.STY(r.r4, l.addr(rpy_errno, r.r3))
Example #13
0
 def read_real_errno(self, save_err):
     if save_err & rffi.RFFI_SAVE_ERRNO:
         # Just after a call, read the real 'errno' and save a copy of
         # it inside our thread-local '*_errno'.  Registers r4-r10
         # never contain anything after the call.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.ld(r.r9.value, r.SP.value, THREADLOCAL_ADDR_OFFSET)
         self.mc.ld(r.r10.value, r.r9.value, p_errno)
         self.mc.lwz(r.r10.value, r.r10.value, 0)
         self.mc.stw(r.r10.value, r.r9.value, rpy_errno)
Example #14
0
 def write_real_errno(self, save_err):
     if save_err & rffi.RFFI_READSAVED_ERRNO:
         # Just before a call, read '*_errno' and write it into the
         # real 'errno'.  A lot of registers are free here, notably
         # r11 and r0.
         if save_err & rffi.RFFI_ALT_ERRNO:
             rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
         else:
             rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.ld(r.r11.value, r.SP.value,
                    THREADLOCAL_ADDR_OFFSET + self.subtracted_to_sp)
         self.mc.lwz(r.r0.value, r.r11.value, rpy_errno)
         self.mc.ld(r.r11.value, r.r11.value, p_errno)
         self.mc.stw(r.r0.value, r.r11.value, 0)
     elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
         # Same, but write zero.
         p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
         self.mc.ld(r.r11.value, r.SP.value,
                    THREADLOCAL_ADDR_OFFSET + self.subtracted_to_sp)
         self.mc.ld(r.r11.value, r.r11.value, p_errno)
         self.mc.li(r.r0.value, 0)
         self.mc.stw(r.r0.value, r.r11.value, 0)
Example #15
0
    def read_real_errno(self, save_err):
        """This occurs after emit_raw_call() and after restore_stack_pointer().
        """
        mc = self.mc

        if save_err & rffi.RFFI_SAVE_ERRNO:
            # Just after a call, read the real 'errno' and save a copy of
            # it inside our thread-local '*_errno'.  Most registers are
            # free here, including the callee-saved ones, except 'ebx'.
            # The tlofs register might have been loaded earlier and is
            # callee-saved, so it does not need to be reloaded.
            if save_err & rffi.RFFI_ALT_ERRNO:
                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
            else:
                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()  # => esi or r12 (possibly reused)
            mc.MOV_rm(edi.value, (tlofsreg.value, p_errno))
            mc.MOV32_rm(edi.value, (edi.value, 0))
            mc.MOV32_mr((tlofsreg.value, rpy_errno), edi.value)

        if handle_lasterror and (
                save_err &
            (rffi.RFFI_SAVE_LASTERROR | rffi.RFFI_SAVE_WSALASTERROR)):
            if save_err & rffi.RFFI_SAVE_LASTERROR:
                from rpython.rlib.rwin32 import _GetLastError
                adr = llmemory.cast_ptr_to_adr(_GetLastError)
            else:
                from rpython.rlib._rsocket_rffi import _WSAGetLastError
                adr = llmemory.cast_ptr_to_adr(_WSAGetLastError)
            GetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
            assert isinstance(self, CallBuilder32)  # Windows 32-bit only
            #
            if save_err & rffi.RFFI_ALT_ERRNO:
                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
            else:
                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
            self.save_result_value(save_edx=True)  # save eax/edx/xmm0
            self.result_value_saved_early = True
            mc.CALL(imm(follow_jump(GetLastError_addr)))
            #
            tlofsreg = self.get_tlofs_reg()  # => esi (possibly reused)
            mc.MOV32_mr((tlofsreg.value, lasterror), eax.value)
Example #16
0
    def read_real_errno(self, save_err):
        """This occurs after emit_raw_call() and after restore_stack_pointer().
        """
        mc = self.mc

        if save_err & rffi.RFFI_SAVE_ERRNO:
            # Just after a call, read the real 'errno' and save a copy of
            # it inside our thread-local '*_errno'.  Most registers are
            # free here, including the callee-saved ones, except 'ebx'.
            # The tlofs register might have been loaded earlier and is
            # callee-saved, so it does not need to be reloaded.
            if save_err & rffi.RFFI_ALT_ERRNO:
                rpy_errno = llerrno.get_alt_errno_offset(self.asm.cpu)
            else:
                rpy_errno = llerrno.get_rpy_errno_offset(self.asm.cpu)
            p_errno = llerrno.get_p_errno_offset(self.asm.cpu)
            tlofsreg = self.get_tlofs_reg()   # => esi or r12 (possibly reused)
            mc.MOV_rm(ecx.value, (tlofsreg.value, p_errno))
            mc.MOV32_rm(ecx.value, (ecx.value, 0))
            mc.MOV32_mr((tlofsreg.value, rpy_errno), ecx.value)

        if handle_lasterror and (save_err & (rffi.RFFI_SAVE_LASTERROR |
                                             rffi.RFFI_SAVE_WSALASTERROR)):
            if save_err & rffi.RFFI_SAVE_LASTERROR:
                from rpython.rlib.rwin32 import _GetLastError
                adr = llmemory.cast_ptr_to_adr(_GetLastError)
            else:
                from rpython.rlib._rsocket_rffi import _WSAGetLastError
                adr = llmemory.cast_ptr_to_adr(_WSAGetLastError)
            GetLastError_addr = self.asm.cpu.cast_adr_to_int(adr)
            assert isinstance(self, CallBuilder32)    # Windows 32-bit only
            #
            if save_err & rffi.RFFI_ALT_ERRNO:
                lasterror = llerrno.get_alt_lasterror_offset(self.asm.cpu)
            else:
                lasterror = llerrno.get_rpy_lasterror_offset(self.asm.cpu)
            self.save_result_value(save_edx=True)   # save eax/edx/xmm0
            self.result_value_saved_early = True
            mc.CALL(imm(follow_jump(GetLastError_addr)))
            #
            tlofsreg = self.get_tlofs_reg()    # => esi (possibly reused)
            mc.MOV32_mr((tlofsreg.value, lasterror), eax.value)