查看: 3769|回复: 3

[原创发布] 【应该是XP/VX/VA通用】TCC for RGSS

[复制链接]
梦石
1
星屑
644
在线时间
277 小时
注册时间
2008-3-30
回帖
65

R考场第七期铜奖

发表于 2020-5-5 15:23:50 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 gjz010 于 2020-5-5 15:35 编辑

因为前两天有群友提出“Ruby和C交互太麻烦了”(又是pack struct又是dll),
想到“和C交互最容易的当然还是C”,突然就做了个这玩意。
把Bellard大手子的libtcc魔改了一份,正好塞进一个dll里(见附件)。
经过tcc加持以后,可以在运行时编译/连接/运行C代码片段。
应该也可以当单独的连接器使用(编译出静态库然后在RGSS里重定位,而非编译成DLL),感觉比Win32API调DLL要舒服一些。

完整脚本:
[pre lang="ruby" file="tcc.rb"]=begin
###############################################################
TCC Compiler for RGSS, v0.0.1
TCC original author: Fabrice Bellard
Porting: gjz010

Modified TCC source: https://github.com/gjz010/tcc-nofs]https://github.com/gjz010/tcc-nofs
UVFS source: https://github.com/gjz010/uvfs-tcc]https://github.com/gjz010/uvfs-tcc
###############################################################
API Document
###############################################################
TCC::Compiler
-----------------
The main wrapper class for using compiler.

Methods:

logs, set_options, add_include_path, add_library_path, add_library,
compile, define_macro, undef_macro, add_symbol, relocate,
get_symbol, get_cwp_symbol, dispose

CallWndProc
-----------------
Three variants of CallWndProc are provided:
TCC::call_window_proc_pl(addr, a, b=0)  # Call with one buffer and one integer.
TCC::call_window_proc(addr, a=0, b=0)   # Call with two integers.
TCC::call_window_proc_pp(addr, a, b)    # Call with two buffers.

On stdlib
-----------------
The porting provides under a virtual internal filesystem called UVFS.
In most time you don't need to care about how UVFS works.

The stdlib provides tcc-libraries as-is:
tcc@uvfs://include
tcc@uvfs://include/winapi
tcc@uvfs://lib/{gdi32.def, kernel32.def, libtcc1.a, msvcrt.def, user32.def}
tcc@uvfs://lib/libtcc # Dangerous! Not the same as this libtcc, and not recommended.


On relocation
-----------------
Imported data may require dllimport to work. See libtcc examples.
CallWndProc-supported callback results in name-mangling.
Use get_cwp_symbol instead.

TCC::TCC_Raw
-----------------

Raw APIs for TCC. Use this if you are confident.
All methods are prefixed with "r_".

###############################################################
Usage
###############################################################

# The C source code.
SCRIPT= <<EOF
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
LRESULT CALLBACK foo(HWND a, UINT b, WPARAM c, LPARAM d){
    char* buf=malloc(1024);
    sprintf(buf, "Warm welcome from TCC!, %d+%d=%d\n", c, d, c+d);
    MessageBox(0, buf, "Hi!", MB_OK);
    free(buf);
    return 0;
}

EOF

# Compiler options.
compiler=TCC::Compiler.new.set_options("-O2 -Wall -pedantic -Werror").
          add_library("user32"). # Add user32 for MessageBox.
          compile(SCRIPT). # Compile the string.
          relocate # And then relocate.
         
# Call the compiled function with CallWindowProc.
TCC::call_window_proc(compiler.get_cwp_symbol("foo"), 1, 2)

# Dispose the compiler.
compiler.dispose
###############################################################
Known Issues
###############################################################

1. "-Werror" not working.
2. Bad options into set_options will cause a silent exit.

###############################################################
=end
module TCC
  # Raw calls to TCC Compiler.
  module TCC_Raw
    TCC_CALLS_TABLE =
    [
      ["L",:r_tcc_new, "V"],
      ["V",:r_tcc_delete, "L"],
      ["V",:r_tcc_set_lib_path, "LP"],
      ["V",:r_tcc_set_error_func, "LLL"],
      ["V",:r_tcc_set_options, "LP"],
      ["L",:r_tcc_add_include_path, "LP"],
      ["L",:r_tcc_add_sysinclude_path, "LP"],
      ["V",:r_tcc_define_symbol, "LPP"],
      ["V",:r_tcc_undefine_symbol, "LP"],
      ["L",:r_tcc_add_file, "LP"],
      ["L",:r_tcc_compile_string, "LP"],
      ["L",:r_tcc_set_output_type, "LL"],
      ["L",:r_tcc_add_library_path, "LP"],
      ["L",:r_tcc_add_library, "LP"],
      ["L",:r_tcc_add_symbol, "LPL"],
      ["L",:r_tcc_output_file, "LP"],
      ["L",:r_tcc_run, "LLP"],
      ["L",:r_tcc_relocate, "LL"],
      ["L",:r_tcc_get_symbol, "LP"],
      ["V",:initialize_uvfs, "V"]
    ]
    for v in TCC_CALLS_TABLE
      begin
        api=Win32API.new "libtcc.dll",v[1].to_s,v[2],v[0]
        lambda {|a| define_method(v[1]) do |*args| a.call(*args) end}.call(api)
      end
    end
    TCC_OUTPUT_MEMORY = 1
    TCC_OUTPUT_EXE = 2
    TCC_OUTPUT_DLL = 3
    TCC_OUTPUT_OBJ = 4
    TCC_OUTPUT_PREPROCESS = 5
   
    TCC_RELOCATE_AUTO = 1
    # CWP for calling into function.
    CallWindowProc = Win32API.new 'user32', 'CallWindowProcW', 'pLLLL', 'L'
    CallWindowProcPL = Win32API.new 'user32', 'CallWindowProcW', 'pLLPL', 'L'
    CallWindowProcPP = Win32API.new 'user32', 'CallWindowProcW', 'pLLPP', 'L'
    extend self
  end
  TCC_Raw::initialize_uvfs()
  
  class IllegalStateError  < StandardError
  end
  class CompileError  < StandardError
    attr_reader :log
    def initialize(log)
      @log=log
    end
    def to_s
      @log.to_s
    end
  end
  class RelocationError  < StandardError
    attr_reader :log
    def initialize(log)
      @log=log
    end
    def to_s
      @log.to_s
    end
  end
  class Compiler
    STATE_IDLE=0
    STATE_COMPILED=1
    STATE_RELOCATED=2
    STATE_READY=3
    def initialize
      @s=TCC_Raw::r_tcc_new()
      @state=0
      initialize_error_handler
      TCC_Raw::r_tcc_set_lib_path(@s, "nul@uvfs://")
      add_include_path("tcc@uvfs://include").
          add_include_path("tcc@uvfs://include/winapi").
          add_library_path("tcc@uvfs://lib")
      TCC_Raw::r_tcc_set_output_type(@s, TCC_Raw::TCC_OUTPUT_MEMORY)
      @buffer=[]
    end
    def logs
      @buffer
    end
    def initialize_error_handler
      # Do nothing.
    end
    def fetch_log
      # Do nothing
    end
    def add_include_path(path)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_add_include_path(@s, path)
      
      return self
    end
    def add_library_path(path)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_add_library_path(@s, path)
      return self
    end
    def add_library(lib)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_add_library(@s, lib)
      return self
    end
    def set_options(options)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_set_options(@s, options)
      return self
    end
    def compile(script)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      ret=TCC_Raw::r_tcc_compile_string(@s, script)
      fetch_log
      if ret==-1
        raise (CompileError.new(@buffer))
      end
      @state=STATE_COMPILED
      return self
    end
    def define_macro(sym, v)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_add_symbol(@s, sym, v)
      return self
    end
    def undef_macro(sym)
      if @state!=STATE_IDLE
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_undefine_symbol(@s, sym)
      return self
    end
    def add_symbol(sym, addr)
      if @state!=STATE_COMPILED
        raise IllegalStateError.new
      end
      TCC_Raw::r_tcc_add_symbol(@s, sym, addr)
      return self
    end
    def relocate
      if @state!=STATE_COMPILED
        raise IllegalStateError.new
      end
      ret=TCC_Raw::r_tcc_relocate(@s, TCC_Raw::TCC_RELOCATE_AUTO)
      fetch_log
      if ret<0
        raise (RelocationError.new(@buffer))
      end
      @state=STATE_READY
      return self
    end
    def dispose
      TCC_Raw::r_tcc_delete(@s)
    end
    def get_symbol(sym)
      if @state!=STATE_READY
        raise IllegalStateError.new
      end
      s=TCC_Raw::r_tcc_get_symbol(@s, sym)
      s
    end
    def get_cwp_symbol(sym)
      get_symbol("_"+sym+"@16")
    end
  end
  def call_window_proc(addr, a=0, b=0)
    TCC_Raw::CallWindowProc.call addr,0,0,a,b
  end
  def call_window_proc_pl(addr, a, b=0)
    TCC_Raw::CallWindowProcPL.call addr,0,0,a,b
  end
  def call_window_proc_pp(addr, a, b)
    TCC_Raw::CallWindowProcPP.call addr,0,0,a,b
  end
  

  def log_handler
    tcc=TCC::Compiler.new.compile( <<EOF
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* buffer=0;
void tcc_error_handler(void* arg, const char* msg){
   
    int n=0;
    if(buffer==0){
      n=strlen(msg)+2;
      buffer=malloc(n);
      strcpy(buffer, msg);
      buffer[n-2]='\n';
      buffer[n-1]=0;
    }else{
      n=strlen(msg)+2+strlen(buffer);
      buffer=realloc(buffer, n);
      strcat(buffer, msg);
      buffer[n-2]='\n';
      buffer[n-1]=0;
    }

   
}

LRESULT CALLBACK move_tcc_log(HWND a, UINT b, WPARAM addrlog, LPARAM d){
    if(buffer==0) return 0;
    if(addrlog==0){
        return strlen(buffer)+1;
    }else{
        strcpy(addrlog, buffer);
        free(buffer);
        int l=strlen(buffer)+1;
        buffer=0;
        return l;
    }
}
EOF
    ).relocate
    handler=tcc.get_symbol("tcc_error_handler")
    moveback=tcc.get_cwp_symbol("move_tcc_log")
    {:handler=>handler, :moveback=>moveback}
  end
  extend self
  
  LOG_HANDLER = TCC::log_handler
  
  class Compiler
    def initialize_error_handler
      TCC_Raw::r_tcc_set_error_func(@s, 0, LOG_HANDLER[:handler])
    end
    def fetch_log
      len=TCC::call_window_proc(LOG_HANDLER[:moveback])
      if len==0
        return false
      end
      buffer = 0.chr * len
      TCC::call_window_proc_pl(LOG_HANDLER[:moveback], buffer)
      @buffer+=(buffer.split "\n")
      return true
    end
  end
  
end

[/pre]

需要libtcc.dll:
libtcc.7z (1.26 MB, 下载次数: 45)

评分

参与人数 3赞 +3 收起 理由
kirh_036 + 1 不明觉醋
574656549 + 1 塞糖 但是很残
有丘直方 + 1 精品文章

查看全部评分

广告位招租
以下为广告位:
1、TCC for RGSS
2、空
3、空
4、空
5、空
梦石
0
星屑
1944
在线时间
404 小时
注册时间
2015-8-30
回帖
322
发表于 2020-5-5 15:28:45 | 显示全部楼层
螃蟹公 nb
回复

使用道具 举报

梦石
0
星屑
4216
在线时间
619 小时
注册时间
2013-4-30
回帖
111
发表于 2020-5-5 20:51:08 | 显示全部楼层
tql 前排
回复

使用道具 举报

头像被屏蔽
梦石
0
星屑
172
在线时间
935 小时
注册时间
2010-11-13
回帖
897
发表于 2020-6-6 14:48:52 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部