-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcbframe.html
131 lines (121 loc) · 7.61 KB
/
cbframe.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title> cbframe - callback frames for luajit </title>
<script src="jquery.js"></script>
<script src="jquery-cookie.js"></script>
<script src="jquery-tablesorter.js"></script>
<script src="strftime.js"></script>
<script src="mustache.js"></script>
<script src="config.js"></script>
<script src="main.js"></script>
<link rel="stylesheet" type="text/css" href="templates/reset.css" />
<link rel="stylesheet" type="text/css" href="templates/hack.css" />
<link rel="stylesheet" type="text/css" id="lights_css" />
<script>
var DOCNAME = 'cbframe'
var PROJECT = 'cbframe'
//set the lights before rendering starts
set_lights()
</script>
</head>
<body>
<header>
<div class="container">
<div class="btn-container btn-lights-container">
<a href="#" class="btn btn-lights" id="lights">lights</a>
</div>
<div class="btn-container btn-home-container">
<a href="/" class="btn btn-home">luapower</a>
</div>
<table id="header_table">
<tr>
<td style="vertical-align: middle;" width="100%">
<h1> cbframe </h1>
<h2> callback frames for luajit </h2>
</td>
<td style="vertical-align: middle;" align="right" style="height: 150px">
<table><tr><td>
<div class="doc" id="package_info_container">
<div id="package_info"> </div>
<div id="commit_log"> </div>
</div>
<a href="https://github.com/luapower/cbframe" class="btn btn-rightside btn-github"><span class="icon"></span>View on GitHub</a>
</td></tr><tr><td>
<a href="https://github.com/luapower/cbframe/tarball/master" class="btn btn-rightside">Download as .tar.gz</a>
</td></tr><tr><td>
<a href="https://github.com/luapower/cbframe/zipball/master" class="btn btn-rightside">Download as .zip</a>
</td></tr></table>
</td>
</tr>
</table>
<div class="btn-container btn-discuss-container">
<a href="https://github.com/luapower/cbframe/issues/new" target="_blank"
class="btn btn-rightside btn-discuss"><span class="icon"></span>Discuss</a>
</div>
</div>
</header>
<div class="bg-container">
<div class="bg-center-container">
<div class="bg bg-cbframe" style="background-image: url('bg/cbframe.png');"></div>
</div>
</div>
<div class="under-header">
<div class="container">
<div id="toc_container" class="toc_container doc"></div>
<button id=tab1_button class="tab_button hidden">Documentation</button>
<button id=tab2_button class="tab_button hidden">Package Info</button>
<div id="tabs_cointainer">
<div id="tab1_container">
<section class="doc">
<span id="module_info"></span>
<h2 id="local-cbframe-requirecbframe"><code>local cbframe = require'cbframe'</code></h2>
<p>Cbframe is a low-level helper module for the luajit ffi for creating ABI-agnostic callbacks. I made it as a workaround for the problem of creating callbacks with pass-by-value struct args and return values in <a href="objc.html">objc</a>.</p>
<p>Works with x86 and x64 Windows, Linux and OSX.</p>
<p>The idea is simple: your callbacks receive the <a href="https://github.com/luapower/cbframe/blob/master/cbframe_x86_h.lua">full state of the CPU</a> (all registers, and CPU flags even), you can modify the state any way you want, and the CPU will be set with the modified state before the callback returns. It's up to you to pick the function arguments from the right registers and/or stack, and to put the return value into the right registers and/or stack, according to the calling convention rules for your platform/compiler.</p>
<p>You can use it to implement a full ABI in pure Lua by leveraging <a href="ffi_reflect.html">ffi_reflect</a>. Or, if you only have a few problematic callbacks that you need to work out, like I do, you can discover where the arguments are on a case-by-case basis by inspecting the CPU state via <code>cbframe.dump()</code>.</p>
<p>ABI manuals:</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/k2b2ssfy.aspx">Windows / x86</a></li>
<li><a href="http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx">Windows / x64</a></li>
<li><a href="https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html">OSX / x86</a></li>
<li><a href="http://www.x86-64.org/documentation/abi.pdf">Linux & OSX / x64</a></li>
</ul>
<p>If in doubt, use <a href="http://www.agner.org/optimize/calling_conventions.pdf">Agner Fog</a> (ABIs are a bitch).</p>
<p>Like ffi callbacks, cbframes are limited resources. You can create up to 1024 simultaneous cbframe objects (you can change that limit in the code - callback slots must be pre-allocated; each callback slot is 7 bytes).</p>
<p>The API is simple. You don't even have to provide the function signature :)</p>
<pre class="sourceCode lua"><code class="sourceCode lua"><span class="kw">local</span> <span class="kw">foo</span> <span class="ot">=</span> <span class="kw">cbframe</span><span class="ot">.</span>new<span class="ot">(</span><span class="kw">function</span><span class="ot">(</span><span class="kw">cpu</span><span class="ot">)</span>
<span class="kw">cbframe</span><span class="ot">.</span>dump<span class="ot">(</span><span class="kw">cpu</span><span class="ot">)</span> <span class="co">--inspect the CPU state</span>
<span class="kw">local</span> <span class="kw">arg1</span> <span class="ot">=</span> <span class="kw">cpu</span><span class="ot">.</span><span class="kw">RDI</span><span class="ot">.</span><span class="kw">lo</span><span class="ot">.</span><span class="kw">i</span> <span class="co">--Linux/x64 ABI: int32 arg#1 in RDI</span>
<span class="kw">cpu</span><span class="ot">.</span><span class="kw">RAX</span><span class="ot">.</span><span class="kw">u</span> <span class="ot">=</span> <span class="kw">arg1</span><span class="ot">^</span><span class="dv">2</span> <span class="co">--Linux/x64 ABI: uint64 return value in RAX</span>
<span class="kw">end</span><span class="ot">)</span>
<span class="co">--foo is the callback object, foo.p is the actual function pointer to use.</span>
set_foo_callback<span class="ot">(</span><span class="kw">foo</span><span class="ot">.</span><span class="kw">p</span><span class="ot">)</span>
<span class="co">--cbframes are permanent by default just like ffi callbacks. tie them to the gc if you want.</span>
<span class="kw">ffi</span><span class="ot">.</span>gc<span class="ot">(</span><span class="kw">foo</span><span class="ot">,</span> <span class="kw">foo</span><span class="ot">.</span><span class="kw">free</span><span class="ot">)</span>
<span class="co">--release the callback slot (or reuse it with foo:set(func)).</span>
<span class="kw">foo</span>:free<span class="ot">()</span></code></pre>
<p><strong>NOTE</strong>: In this implementation, the cpu arg is a global variable: if another cbframe callback is triggered from inside a cbframe callback, the original cpu state will get trashed. It's up to you to prevent this by saving the original cpu state before calling the callback-triggering inner function, and restoring it before the parent function returns.</p>
</section>
</div>
<div id="tab2_container" class="doc"></div>
</div>
</div>
<div class="container">
<footer>
<div id="disqus_thread"></div>
<div class="faint">[email protected] | <a href="http://unlicense.org/">public domain</a></div>
</footer>
</div>
</div>
<script type="text/x-mustache" id=info_tab_template>
<h3>Modules</h3>
<ul>
{{#module_array}}
<li>{{name}}</li>
{{/module_array}}
</ul>
</script>
</body>
</html>