3

First Lua code:

local ffi = require "ffi"

ffi.cdef[[
void printc(const char *fmt, ...);
]]
ffi.C.printc("Hello world")

Does not work. Error:

boot.lua:6: /usr/lib64/libluajit-5.1.so.2: undefined symbol: printc

However, the symbol is in fact defined inside the executable that LuaJIT is running from (and the function declaration is copy-pasted from C):

$ nm --defined-only build/a.out | grep printc
00000000000650c1 T printc

My first idea for a solution was to build a shared library with the same symbols as the executable and load it in LuaJIT:

$ cc -fPIC -shared $LDFLAGS $OFILES -o build/a.so

New Lua code:

local ffi = require "ffi"
lib = ffi.load("./build/a.so")
ffi.cdef[[
void printc(const char *fmt, ...);
]]
lib.printc("Hello world")

This allows me to call the printc function. However, there's a very big issue: the loaded library uses a separate memory space from the running program. The buffer that lib.printc("Hello world") is writing to is not the same buffer as the program that LuaJIT is running in uses. It acts as if it's interacting an entirely different process.

printc is supposed to print to the console subsystem of the executable that LuaJIT is running inside of. The console buffer is stored as a global (extern) array of strings, which printc writes to. The global console buffer that LuaJIT gets by loading a.so points to some other memory address than global console buffer of the running a.out program.

So that is not a viable solution. I don't know what I'm supposed to do now. The symbols are being exported as part of my executable but LuaJIT not loading them. I can't ffi.load my executable either:

lib = ffi.load("./build/a.out")

boot.lua:2: ./build/a.out: cannot dynamically load position-independent executable

How can I get the LuaJIT FFI to load symbols from my running executable?

Accumulator
  • 873
  • 1
  • 13
  • 34
  • Not an expert, but try `objdump -t ./build/a.out` and see if the symbol even exists in the executable :) – DarkWiiPlayer Jan 16 '20 at 09:01
  • You probably need to export symbols from the executable by using `-Wl,-E` when linking. – lhf Jan 16 '20 at 09:37
  • @DarkWiiPlayer that's what `nm --defined-only does`. Here is `objdump -t build/a.out| grep printc`: `000000000001abd1 g F .text 0000000000000179 printc` – Accumulator Jan 16 '20 at 17:20
  • The suggestions to use `-E` didn't work, but it led me to finding the `-rdynamic` flag which did fix the issue. – Accumulator Jan 16 '20 at 17:44

1 Answers1

1

Passing the -rdynamic flag to cc fixes the issue, allowing LuaJIT to run ffi.C.* functions from the program.

Accumulator
  • 873
  • 1
  • 13
  • 34
  • For something approaching a TL;DR rationale for this answer, ^F https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html for "export-dynamic". gcc passes this option to ld(/collect2) during linking when -rdynamic is specified. – i336_ May 05 '21 at 07:39