`
RednaxelaFX
  • 浏览: 3049083 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

在Windows上使用Wilson

    博客分类:
  • Ruby
阅读更多
之前被NS老兄激起了兴趣发过beef帖,主要是显示可以很容易的写出Ruby扩展用于直接生成机器码,连接到Ruby的对象系统上,然后像调用普通Ruby方法一样去使用。我觉得这个很有趣,想看看有没有好的办法做个internal DSL出来在Ruby里写类似MASM语法的汇编,然后让Bk201生成机器码出来执行。

昨天看到某帖之后又把我的兴趣激起来了……在动手实现DSL之前,我先搜了一下Ruby assembler,发现Ryan Davis写了个叫Wilson的库,功能跟我想要的很类似,虽然语法有点不同,好歹还是NASM而不是AT&T式的。当前版本是1.1.1。我现在是在Windows XP SP3/Ruby 1.8.6上测试的。

安装该库用:
gem install wilson

加载该库用require 'wilson'。它会对Ruby一些核心类做monkey patch,要注意。

原本Wilson是为在Mac上使用而编写,但整个代码都是纯Ruby的,所以在Windows上使用稍微修改一下平台相关的代码就行。在ruby安装目录的gems/1.8/gems/wilson-1.1.1/lib/目录下,
wilson.rb,第1135-1136行:
  dir = File.join(Config::CONFIG["prefix"], "lib")
  dlload File.join(dir, "libruby.dylib")

.dylib是Mac上的动态链接库文件的后缀。这里要改为:
  dir = File.join(Config::CONFIG["prefix"], "bin")
  dlload File.join(dir, Config::CONFIG["LIBRUBY_SO"])

就可以在Windows上正常使用了。

Wilson在一些测试里会使用到RubyInline,有兴趣的话也可以装上:
gem install rubyinline

加载该库用require 'inline'。


如果把MASM语法下op dest, src的形式看作前缀表达式,那么Wilson的DSL表现出来的就是dest.op src形式的“中缀表达式”。所以原本写作xor eax, eax的汇编,在Wilson就写作eax.xor eax。习惯了之后这么写也挺顺的。
让我们来看看Wilson in action~
require 'rubygems'
require 'wilson'

class A
  defasm :add, :a, :b do
    a, b = arg(0), arg(1)
    eax.mov a
    eax.add b
    eax.dec
  end
  
  defasm :ary_len, :ary do
    ary = arg(0)
    eax.mov ary
    eax.add 4*2           # skip RBasic.flags and RBasic.klass
    eax.mov eax.m
    to_ruby eax
  end
  
  defasm :ary_store, :ary, :idx, :val do
    ary, idx, val = arg(0), arg(1), arg(2)
    eax.mov ary
    ecx.mov(eax + 4*4)    # address of RArray.ptr
    edx.mov idx
    from_ruby edx
    edx.shl 2
    ecx.add edx
    edx.mov val
    ecx.m.mov edx
  end
end

a = A.new
p a.add(3, 5)             #=> 8
p a.ary_len([])           #=> 0
p a.ary_len([2, 4, 6, 8]) #=> 4
ary = [1, 2, 3]
a.ary_store(ary, 2, 4)    #=> [1, 2, 4]
p ary                     #=> [1, 2, 4]

Wilson的实现暂时还不太完善,例如说声明一个汇编方法用defasm,其参数包括生成方法的名字和参数列表(的名字),但在定义方法体时却暂时还无法用名字与引用参数,只能通过arg(0)、arg(1)之类的形式去引用。寻址模式中放大倍数的版本也都还没实现,上面代码中的ary_store本来可以用lea ecx, dword ptr [ecx + edx*4]一条指令完成一个乘法和一个加法,但Wilson还不支持edx*4的形式,非要用的话只好如下所示:
class A
  defasm :ary_store, :ary, :idx, :val do
    ary, idx, val = arg(0), arg(1), arg(2)
    eax.mov ary
    ecx.mov(eax + 4*4)  # RArray.ptr
    edx.mov idx
    from_ruby edx
    # ecx.lea(ecx + edx*4) # this is not supported by Wilson yet
    # hack: lea  ecx, dword ptr [ecx + edx*4]
    self.stream.concat [0x8D, 0x0C, 0x91]
    edx.mov val
    ecx.m.mov edx
  end
end

把机器码硬插到stream里……OTL

另外Wilson在把某些指令汇编到机器码时有问题。我试过跟ebx相关的几条指令,生成出来的都是错的:(测试摘自Wilson里的test_wilson.rb,注释是我添加的)
  def test_mov_ebx_m_ecx_edx_offset
    # mov  ebx, dword ptr [ecx + edx + 1]
    # 8B 5C 11 01
    asm.ebx.mov(asm.ecx + asm.edx + 1)
    # this test looks broken
    # 8B 1C 51 01   # wrong machine code
    assert_equal [0x8B, 0b00011100, 0b01010001, 1], stream
  end

  def test_mov_ebx_m_ecx_edx_big_offset
    # mov  ebx, dword ptr [ecx + edx + 256]
    # 8B 9C 11 00 01 00 00
    asm.ebx.mov(asm.ecx + asm.edx + 256)
    # this test looks broken as well...
    # 8B 1C 91 00 01 00 00   # wrong machine code
    assert_equal [0x8B, 0b00011100, 0b10010001, 0, 1, 0, 0], stream
  end

  def test_mov_m_ecx_edx_offset_ebx
    # mov  dword ptr [ecx + edx + 1], ebx
    # 89 5C 11 01
    (asm.ecx + asm.edx + 1).mov asm.ebx
    # this test looks broken
    # 89 1C 51 01    # is everything related to ebx broken?
    assert_equal [0x89, 0b00011100, 0b01010001, 1], stream
  end

为什么作者的测试用例里assert的数据就已经跟我所知道的机器码不一致了 OTL
回头我把它修修看看有没有必要发个patch过去……人家或许对Windows没兴趣,顺带就对这patch没兴趣了 =v=

顺带说说上面的例子是如何能运行的。注意到我什么错误检查都没做,所以传入的参数跟我预期的使用方式不符的话程序基本上就要crash了。

第一个例子比较直观,只有最后的dec eax指令可能有点怪。这是因为Ruby的Fixnum表现的是31位带符号整数,普通的31位补码表示的整数要转换为Fixnum的公式是(n << 1) + 1。例子中a与b都是Fixnum,它们的高31位就是原本的数值,而末尾的1则是Fixnum的tag。把它们直接相加,虽然高位是对位加起来了,但末尾的tag本来不该参与运算却也相加了,于是通过dec eax指令把多加的tag再减回去。

后两个例子都涉及到CRuby中对象布局的实现细节。CRuby 1.8.6里有这两个结构体:
struct RBasic {
    unsigned long flags;
    VALUE klass;
};

struct RArray {
    struct RBasic basic;
    long len;
    union {
        long capa;
        VALUE shared;
    } aux;
    VALUE *ptr;
};

数组对象的背后就是靠RArray结构体来支撑的,而它的开头又包含了一个RBasic结构体。可以把RBasic看作是所有Ruby对象都有的header。由此可以知道,在32位x86上,RArray的len成员位于偏移量4*2 == 8的位置上,表示该数组对象的长度(元素个数);ptr成员位于偏移量4*4 == 16的位置上,它所指向的就是数组的实际内容,是一大块连续的空间。

在第二个例子,ary_len里,首先把第一个参数放入eax中。这个参数是指向一个RArray实例的指针。然后再把eax += 8,得到RArray.len的地址。接着通过mov eax, dword ptr [eax]指令,把RArray.len的值取出来。最后使用to_ruby“宏”将数字转换为Ruby的Fixnum,返回。

在第三个例子,ary_store里,过程跟前一个例子差不多,关键思路是达到RARRAY(ary)->ptr[idx] = val的目的。

OK,可以靠Wilson做点更有趣的事情了 ^ ^
分享到:
评论
2 楼 RednaxelaFX 2009-09-20  
night_stalker 写道
硬插也没什么不好 …… AOT 而已 ……

用上硬插,状况就跟Bk201的现状差不多了 
1 楼 night_stalker 2009-09-20  
硬插也没什么不好 …… AOT 而已 ……

相关推荐

    go1.9.2.windows-amd64.msi

    标题中的"Go1.9.2.windows-amd64.msi"是指Go编程语言的1.9.2版本在Windows操作系统上使用的64位安装程序。Go,也被称为Golang,是由Google开发的一种静态类型的、编译式的、跨平台的编程语言。它设计简洁、高效,...

    Wilson.Win32.IO

    "Wilson.Win32.IO" 是一个专为解决`PathTooLongException`问题的源代码库,它几乎重新实现了 .NET Framework ...此外,对于跨平台的应用,需要考虑在非Windows系统上的适配,因为它们可能不接受长路径或使用不同的API。

    Windows PowerShell Step by Step ( PDFDrive.com ).pdf

    本书《Windows PowerShell Step by Step》(第三版)由微软官方认证专家 Ed Wilson 撰写,是学习 Windows PowerShell 的权威指南。本书全面覆盖了 Windows PowerShell 5.0 的新特性和高级功能,并通过逐步指导的方式...

    pywd2015-qt5:用Python为Wilson编写的Qt5 GUI-Devinney蚀二进制建模软件

    在Windows上,多个Python安装可能会相互冲突,并且您的“ python”命令可能会运行不同的版本,而不是您打算的版本。 从命令行运行“ python --version”以检查您的Python版本。 PyWD2015支持Pyt

    windows汇编编译器

    在Windows上,虽然系统调用机制不同,但基本思路相似,需要调用Windows API函数,如`WriteFile`和`ExitProcess`。 编译汇编程序时,你可以使用Yasm命令行工具: ```bash yasm -f win32 hello.asm -o hello.obj ```...

    windows powershell 2.0. best practices

    根据给定文件的信息,我们可以总结出关于《Windows PowerShell 2.0 Best Practices》一书的重要知识点,本书由Ed Wilson撰写并由Microsoft Press于2010年出版。 ### 关键知识点概览 #### 1. **Windows PowerShell ...

    windows下gcc编译

    在Windows上使用GCC通常涉及到MinGW(Minimalist GNU for Windows)或MSYS2等环境,它们提供了与Linux类似的编译环境。 1. **MinGW**: MinGW是GCC在Windows上的一个移植版本,它包含了头文件、库以及Gnu工具集,...

    go1.9.2.windows-amd64

    这些内容组合在一起,构成了一个完整的Go语言开发环境,使得开发者能够在Windows平台上进行Go语言的应用开发。 总之,"go1.9.2.windows-amd64"是一个适用于64位Windows系统的Go语言版本,通过提供的MSI安装文件,...

    采用windows IME 机制编写拼音输入法C语言源码

    在学习和使用这份源码时,开发者可以了解如何利用Windows API与操作系统交互,实现输入法的核心功能。此外,通过阅读和理解源码,还可以学习到C语言在处理复杂逻辑和用户界面方面的技巧。对于希望开发自己的输入法...

    Windows Scripting Self-Paced Learning Guide

    《Windows Scripting Self-Paced Learning Guide》是一本由Microsoft Press出版的专业书籍,作者为Ed Wilson。该书旨在为读者提供一个系统学习Windows脚本编程的方法。通过本书的学习,读者可以掌握Windows环境下...

    def-guide-to-win-installer:Phil Wilson的“ Windows安装程序权威指南”的源代码-windows source code

    使用绿色按钮将文件下载为zip格式,或使用Git将存储库克隆到您的计算机上。 发行版 版本v1.0对应于已出版书籍中的代码,没有更正或更新。 会费 请参阅文件Contributing.md,以获取有关如何为该存储库做出贡献的更多...

    MS.Windows.PowerShell.Best.Practices PDF

    它为读者提供了深入理解和高效使用Windows PowerShell所需的知识和技巧。本书覆盖了从基础知识到高级主题的广泛内容,适合不同层次的学习者。 #### 书籍结构与主要内容 本书分为两个主要部分:理解Windows ...

    Windows.PowerShell.3.0.Step.by.Step

    本书由Ed Wilson编写,并获得微软公司的授权出版,旨在帮助读者深入了解和掌握Windows PowerShell 3.0的强大功能。 ### 一、Windows PowerShell 3.0概述 在第一章“Windows PowerShell 3.0概述”中,作者首先介绍...

    MCSE70-270 windows xp 教材

    - **收购协调员**:Jessica Wilson。 - **全球业务发展副总裁**:Richard Kristof。 - **技术编辑**:Rory McCaw。 - **校对编辑**:Carl Wikander。 - **索引编制者**:Jack Lewis。 - **生产和编辑服务**:Apollo ...

    don w. wilson-开源

    9. `Howtoinstall.txt`:安装指南,提供了关于如何在用户的系统上安装和运行这个图形查看器的步骤。 综上所述,Don W. Wilson的开源项目是一个用Delphi开发的图形查看器,支持多种图像格式,并且采用了创新的3D绘制...

Global site tag (gtag.js) - Google Analytics