Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use dynasm to optimize ndpi binding functions
Dynasm is used to construct a wrapper function that avoids a struct return (that LuaJIT does not support for traced FFI calls) by using a struct pointer. We use dynasm to avoid having to compile a C wrapper which complicates the build process. The wrapper isn't expressible in Lua.
- Loading branch information
Showing
2 changed files
with
115 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
-- This module creates a wrapper around nDPI's packet processing | ||
-- functions in order to help LuaJIT do its optimizations | ||
-- | ||
-- Specifically, it avoids a struct value return by creating wrappers | ||
-- that pass a struct pointer in instead. LuaJIT can handle that | ||
-- better than a struct return (which is not supported). | ||
|
||
module(..., package.seeall) | ||
|
||
local dasm = require("dasm") | ||
local ffi = require("ffi") | ||
local ndpi = require("ndpi.c").lib | ||
|
||
local debug = false | ||
|
||
|.arch x64 | ||
|.actionlist actions | ||
|
||
-- the definitions here (anchor, assemble, gen) are borrowed from lwaftr | ||
-- (see multi_copy.lua) | ||
__anchor = {} | ||
|
||
local function assemble (name, prototype, generator) | ||
local Dst = dasm.new(actions) | ||
generator(Dst) | ||
local mcode, size = Dst:build() | ||
table.insert(__anchor, mcode) | ||
if debug then | ||
print("mcode dump: "..name) | ||
dasm.dump(mcode, size) | ||
end | ||
return ffi.cast(prototype, mcode) | ||
end | ||
|
||
local function gen_nddpw(orig_f) | ||
local function gen(Dst) | ||
-- pass the first stack argument onto the original function | ||
| mov rax, [rsp+8] | ||
| push rax | ||
|
||
-- call the original function, do stack cleanup | ||
| mov64 rax, orig_f | ||
| call rax | ||
| add rsp, 8 | ||
|
||
-- at this point, rax and rdx have struct | ||
-- fields in them, which we want to write into | ||
-- the struct pointer (2nd stack arg) | ||
| mov rcx, [rsp+16] | ||
| mov [rcx], rax | ||
| mov [rcx+4], rdx | ||
|
||
| ret | ||
end | ||
|
||
return gen | ||
end | ||
|
||
local function gen_nupw(orig_f) | ||
local function gen(Dst) | ||
-- call the original function, aligning on 16 | ||
| sub rsp, 8 | ||
| mov64 rax, orig_f | ||
| call rax | ||
| add rsp, 8 | ||
|
||
-- like above, write into struct | ||
| mov rcx, [rsp+8] | ||
| mov [rcx], rax | ||
| mov [rcx+4], rdx | ||
|
||
| ret | ||
end | ||
|
||
return gen | ||
end | ||
|
||
-- see ljndpi/ndpi/c.lua for the corresponding headers for these functions | ||
-- these have an extra void* argument at the end for the struct pointer | ||
local function make_nddp_wrapper(f) | ||
local wrap = assemble("ndpi_detection_process_packet_wrapper", | ||
ffi.typeof("void (*)(void*, void*, void*, unsigned short, uint64_t, void*, void*, void*)"), | ||
gen_nddpw(f)) | ||
return function(self, flow, data, len, tick, src, dst) | ||
local proto = ffi.new("ndpi_protocol_t") | ||
wrap(self, flow, data, len, tick, src, dst, proto) | ||
return proto.master_protocol, proto.protocol | ||
end | ||
end | ||
|
||
local function make_ngup_wrapper(f) | ||
local wrap = assemble("ndpi_detection_process_packet_wrapper", | ||
ffi.typeof("void (*)(void*, uint8_t, uint32_t, uint16_t, uint32_t, uint16_t, void*)"), | ||
gen_nupw(f)) | ||
return function(self, prot_n, src_h, src_p, dst_h, dst_p) | ||
local proto = ffi.new("ndpi_protocol_t") | ||
wrap(self, prot_n, src_h, src_p, dst_h, dst_p, proto) | ||
return proto.master_protocol, proto.protocol | ||
end | ||
end | ||
|
||
process_packet = make_nddp_wrapper(ndpi.ndpi_detection_process_packet) | ||
guess_undetected_protocol = make_ngup_wrapper(ndpi.ndpi_guess_undetected_protocol) |