Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过ctypes byref将Python3接口到NASM_Python_Linux_Nasm_X86 64_Ctypes - Fatal编程技术网

通过ctypes byref将Python3接口到NASM

通过ctypes byref将Python3接口到NASM,python,linux,nasm,x86-64,ctypes,Python,Linux,Nasm,X86 64,Ctypes,我正在将Python3与Linux Mint 18和NASM结合使用,并希望编写直接使用x87 FPU寄存器的汇编代码。我应该指出的是,我是一名硬件工程师,也会编程,而不是程序员。虽然我对python和大多数汇编程序都很在行,但我很少使用C语言,而且在接口方面也不是很在行 搜索之后,我在ActiveState(如下)上找到了一个配方,这让我开始将NASM代码放入内存,并通过值传递int和float 由于我想使用FPU,并且只能从RAM加载FPU,接下来我要做的是在内存中传入一个浮点值,由输入寄存

我正在将Python3与Linux Mint 18和NASM结合使用,并希望编写直接使用x87 FPU寄存器的汇编代码。我应该指出的是,我是一名硬件工程师,也会编程,而不是程序员。虽然我对python和大多数汇编程序都很在行,但我很少使用C语言,而且在接口方面也不是很在行

搜索之后,我在ActiveState(如下)上找到了一个配方,这让我开始将NASM代码放入内存,并通过值传递int和float

由于我想使用FPU,并且只能从RAM加载FPU,接下来我要做的是在内存中传入一个浮点值,由输入寄存器rdi指向,我理解为byref(),计划从[rdi]加载FPU

我已经在下面代码的if name=='main'部分实现了简单的'helloworld'addinteger和move double函数。最后一个函数是我第n次尝试理解(但失败了)通过ctyes向汇编程序传递双byref的语法。我仍然在学习如何理解语法错误消息,以及不太适合这种情况的ctypes示例

有人能帮我举一个正确的例子吗

#!/usr/bin/env python

# python 2 example
# downloaded from http://code.activestate.com/recipes/579037-how-to-execute-x86-64-bit-assembly-code-directly-f/

# change to python 3 only required string.encode to get bytes, and print()

import subprocess, os, tempfile
from ctypes import *

PAGE_SIZE = 4096    

class AssemblerFunction(object):

  def __init__(self, code, ret_type, *arg_types):

    # get handle and file names for temp files
    (fd, source_name) = tempfile.mkstemp(".S", "assembly", os.getcwd())
    object_name = os.path.splitext(source_name)[0]

    # write code string out to source file
    os.write(fd, code.encode('utf-8'))  ## convert code string to code bytes
    os.close(fd)

    # run NASM on the source
    subprocess.check_call(["nasm",source_name])
    # it creates an object file without the extension

    # get the ojbect code
    with open(object_name, 'rb') as fbin:
        binary = fbin.read()     
    bin_len = len(binary)

    # clean up temporary files     
    os.unlink(source_name)
    os.unlink(object_name)

    # align our code on page boundary.
    self.code_buffer = create_string_buffer(PAGE_SIZE*2+bin_len)
    addr = (addressof(self.code_buffer) + PAGE_SIZE) & (~(PAGE_SIZE-1))
    memmove(addr, binary, bin_len)    

    # Change memory protection
    self.mprotect = cdll.LoadLibrary("libc.so.6").mprotect
    mp_ret = self.mprotect(addr, bin_len, 4)   # execute only. 
    if mp_ret: raise OSError("Unable to change memory protection")

    self.func = CFUNCTYPE(ret_type, *arg_types)(addr)
    self.addr = addr
    self.bin_len = bin_len

  def __call__(self, *args):
    return self.func(*args)

  def __del__(self):
    # Revert memory protection
    if hasattr(self,"mprotect"):
      self.mprotect(self.addr, self.bin_len, 3)   


if __name__ == "__main__":

  # input parameters go in via the following registers
  # 1, RDI; 2, RSI; 3, RDX; 4, RCX; 5, R8; 6, R9

  # add integer example, WORKS  
  add_func_2i = """ BITS 64
                    mov rax, rdi    ; Move the first parameter
                    add rax, rsi    ; add the second parameter
                    ret             ; rax will be returned
                    """

  Add_int_2 = AssemblerFunction(add_func_2i, c_int, c_int, c_int)
  print(Add_int_2(1, 2))
  print(Add_int_2(4, 5))

  # move a floating value from input to rax, WORKS
  move_dub = """ BITS 64
                    mov rax, rdi    ; Move the first parameter
                    ret             ; rax will be returned 
                    """

  echo_dub = AssemblerFunction(move_dub, c_double, c_double)
  print(echo_dub(4.321))

# move a floating value from input* to rax, no joy yet
  move_deref_dub = """ BITS 64
                    mov rax, [rdi]    ; Move the first parameter
                    ret               ; rax will be returned 
                    """

  dub_in = c_double(1.0)

  echo_ddub = AssemblerFunction(move_deref_dub, c_double, byref(dub_in))
  print(echo_ddub(54.321))

在Linux上的64位代码中,浮点值将在向量寄存器XMM0到XMM7中传递。并且将返回XMM0/XMM1(不是RAX)中的浮点值。您应该查看64位Linux系统V ABI。你可以在这里查看ABI:(rev 252是最新的64位版本)@MichaelPetch我在跑步之前试着走路,使用的是与x86/x87兼容的最低级别的东西。我用的是i5。我的第二个示例可以工作,使用rdi和rax作为输入/输出寄存器,并且似乎可以工作。您的评论是指rdi和xmm0上的值,还是什么?一旦我能以正确的语法输入输出一些东西,那么我就可以尽情地玩其他所有时髦的东西了。要通过指针传递一个double,那么你需要使用类似于
echo\u ddub=AssemblerFunction的东西(move\u deref\u dub,c\u double,pointer(c\u double))
然后
print(echo\u ddub(c\u doub(54.321)))
在浮点测试的测试代码中,您可以尝试
movsd xmm0,[rdi]
获取
[rdi]
处的64位双浮点数,并将其移动到xmm0寄存器中。作为一个实验,xmm0将使xmm0中的值加倍。XMM0恰好也是用于返回浮点和双精度的向量寄存器。然后你只需要做
ret
。最终结果是它应该打印
108.642
@MichaelPetch,我的意思是我更喜欢显式地传递
byref(c_double(54.321))
。当您在不使用byref的情况下传递
c_double(54.321)
时,您依靠ctypes为您隐式地创建指针,这将很乐意做到,但这会使读取代码时,在不必搜索原型定义的源代码的情况下,对传递的内容产生歧义。