snabbco / snabb

Snabb: Simple and fast packet networking
Apache License 2.0
2.96k stars 298 forks source link

[raptorjit] GC64 versus embedded memory references in DynASM #1302

Open wingo opened 6 years ago

wingo commented 6 years ago

In Snabb we use DynASM to generate assembly at run-time. One thing that we like to do is to embed references to FFI data structures defined in Lua. For example, consider this test file:

local ffi = require("ffi")
local dasm = require("dasm")

local fptr
local asm_status = ffi.new("uint32_t[1]")

print(asm_status)

|.arch x64
|.actionlist actions
local Dst = dasm.new(actions)
| mov dword [asm_status], 0xdeadbeef
| mov eax, 42
| ret
code = Dst:build() -- assign to 'code' to avoid machine code being GC'd
fptr = ffi.cast("int(*)()", code)

print('a')
local ret = fptr()
assert(ret == 42)
print('b')
print("magic number: 0x"..bit.tohex(asm_status[0]))
assert(asm_status[0] == 0xdeadbeef, "bad magic")

Put that in test.dasl. When fptr() is called, it sets the first uint32 in the FFI data asm_status. To run in Snabb, from a build directory, do:

../lib/luajit/src/raptorjit dynasm.lua /tmp/test.dasl > /tmp/test.lua
sudo ./snabb snsh /tmp/test.lua

The test file needs to be run under snabb and not basic raptorjit because it uses the Lua interface to dynasm, which is only built into Snabb at this point.

Anyway making test.lua works fine and does the same as upstream Snabb. However running the file doesn't work:

wingo@sparrow ~/src/raptorjit-snabb/src$ sudo ./snabb snsh /tmp/test.lua
Password: 
cdata<unsigned int [1]>: 0x7f1b69e5ff38
a
snabb[632]: segfault at 0x69e5ff38 ip 0x7f1b6ae77000 sp 0x7fffd31c45f8 code 1 errno 0
Segmentation fault

The reason is because DynASM currently expects embedded constants to be addressable with 32-bit references. As you can see from the printout, 0x7f1b69e5ff38 is outside the 32-bit address space.

In contrast, compare to running the same file with upstream Snabb:

wingo@sparrow ~/src/raptorjit-snabb/src$ sudo ~/src/snabb/src/snabb snsh /tmp/test.lua
cdata<unsigned int [1]>: 0x412390b0
a
b
magic number: 0xdeadbeef

The address is in the lower 32 bits and thus it works.

The difference between RaptorJIT Snabb and upstream Snabb is that RaptorJIT uses GC64. So we need to resolve the incompatibility, allowing RaptorJIT Snabb to use DynASM, by extending RaptorJIT's dynasm.

wingo commented 6 years ago

Or heh, it seems it's just that you can't embed loads from immediate 64-bit addresses. Have to load the immediate address into a register with movq (which has special support for 64-bit immediates), then dereference the register; fair enough.

wingo commented 6 years ago

Blocks https://github.com/snabbco/snabb/pull/1264, fix in the works