[Tarantool-patches] [PATCH] Fix saved bytecode encapsulated in ELF objects.
Sergey Bronnikov
estetus at gmail.com
Mon May 22 11:58:05 MSK 2023
From: Sergey Bronnikov <sergeyb at tarantool.org>
Thanks to Dimitry Andric.
(cherry picked from commit 7dbf0b05f1228c1c719866db5e5f3d58f87f74c8)
Function `bcsave.lua:bcsave_elfobj()` produced an object file in ELF
format with a wrong size size of `.strtab`. Wrong size causes lld to
show an error message similar to: `ld: error: obj/bytecode.o: string
table non-null terminated`.
Sergey Bronnikov:
* added the description and the test for the problem
Signed-off-by: Sergey Bronnikov <sergeyb at tarantool.org>
---
Branch: https://github.com/tarantool/luajit/tree/ligurio/gh-366-strtab-section-correct-size
PR: https://github.com/tarantool/tarantool/pull/8678
---
src/jit/bcsave.lua | 2 +-
.../lj-366-strtab-correct-size.test.lua | 148 ++++++++++++++++++
2 files changed, 149 insertions(+), 1 deletion(-)
create mode 100644 test/tarantool-tests/lj-366-strtab-correct-size.test.lua
diff --git a/src/jit/bcsave.lua b/src/jit/bcsave.lua
index c17c88e0..2553d97e 100644
--- a/src/jit/bcsave.lua
+++ b/src/jit/bcsave.lua
@@ -275,7 +275,7 @@ typedef struct {
o.sect[2].size = fofs(ofs)
o.sect[3].type = f32(3) -- .strtab
o.sect[3].ofs = fofs(sofs + ofs)
- o.sect[3].size = fofs(#symname+1)
+ o.sect[3].size = fofs(#symname+2)
ffi.copy(o.space+ofs+1, symname)
ofs = ofs + #symname + 2
o.sect[4].type = f32(1) -- .rodata
diff --git a/test/tarantool-tests/lj-366-strtab-correct-size.test.lua b/test/tarantool-tests/lj-366-strtab-correct-size.test.lua
new file mode 100644
index 00000000..d4b51537
--- /dev/null
+++ b/test/tarantool-tests/lj-366-strtab-correct-size.test.lua
@@ -0,0 +1,148 @@
+local tap = require('tap')
+local test = tap.test('lj-366-strtab-correct-size'):skipcond({
+ -- Test is ELF-specific and because LuaJIT exports object files in ELF format
+ -- for all operating systems except macOS and Windows we skip test on
+ -- these OSes. See src/jit/bcsave.lua:bcsave_obj.
+ ['Disabled on Windows'] = jit.os == 'Windows',
+ ['Disabled on macOS'] = jit.os == 'OSX',
+})
+
+local ffi = require 'ffi'
+
+-- Reference numbers for strtab offset and size could be obtained with
+-- readelf(1). Note that number system of these number is hexadecimal.
+--
+-- $ luajit -b -n "module_name" -e "print()" xxx.obj
+-- $ readelf --section-headers xxx.obj
+-- There are 6 section headers, starting at offset 0x40:
+--
+-- Section Headers:
+-- [Nr] Name Type Address Offset
+-- Size EntSize Flags Link Info Align
+-- ...
+--
+-- [ 3] .strtab STRTAB 0000000000000000 00000223
+-- 0000000000000017 0000000000000000 0 0 1
+-- ...
+
+local expected_strtab_size = 23 -- == 0x17
+local expected_strtab_offset = 547 -- == 0x223
+
+-- Defined in elf.h.
+local sht_symtab = 2
+
+ffi.cdef[[
+typedef struct {
+ uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
+ uint16_t type, machine;
+ uint32_t version;
+ uint32_t entry, phofs, shofs;
+ uint32_t flags;
+ uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
+} ELF32header;
+typedef struct {
+ uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7];
+ uint16_t type, machine;
+ uint32_t version;
+ uint64_t entry, phofs, shofs;
+ uint32_t flags;
+ uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx;
+} ELF64header;
+typedef struct {
+ uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize;
+} ELF32sectheader;
+typedef struct {
+ uint32_t name, type;
+ uint64_t flags, addr, ofs, size;
+ uint32_t link, info;
+ uint64_t align, entsize;
+} ELF64sectheader;
+typedef struct {
+ uint32_t name, value, size;
+ uint8_t info, other;
+ uint16_t sectidx;
+} ELF32symbol;
+typedef struct {
+ uint32_t name;
+ uint8_t info, other;
+ uint16_t sectidx;
+ uint64_t value, size;
+} ELF64symbol;
+typedef struct {
+ ELF32header hdr;
+ ELF32sectheader sect[6];
+ ELF32symbol sym[2];
+ uint8_t space[4096];
+} ELF32obj;
+typedef struct {
+ ELF64header hdr;
+ ELF64sectheader sect[6];
+ ELF64symbol sym[2];
+ uint8_t space[4096];
+} ELF64obj;
+]]
+
+local is64_arch = {
+ ["x64"] = true,
+ ["arm64"] = true,
+ ["arm64be"] = true,
+ ["ppc"] = false,
+ ["mips"] = false,
+}
+
+local is64 = is64_arch[jit.arch] or false
+local ELFobj_type = ffi.typeof(is64 and "ELF64obj *" or "ELF32obj *")
+local ELFsectheader_type = ffi.typeof(is64 and "ELF64sectheader *" or "ELF32sectheader")
+
+-- Reads a file located in a specified path and returns its content.
+local function read_file(path)
+ local file = assert(io.open(path), 'cannot open an object file')
+ local content = file:read("*a")
+ file:close()
+ return content
+end
+
+-- Parses a buffer in an ELF format and returns an offset and a size of strtab
+-- section for a symtab.
+local function read_elf_strtab(elf_content)
+ local elf = ffi.cast(ELFobj_type, elf_content)
+ local elf_header = elf.hdr
+ local sec_strtab
+ for i = 0, elf_header.shnum do
+ local sec = ffi.cast(ELFsectheader_type, elf.sect[i])
+ if sec.type == sht_symtab then
+ sec_strtab = ffi.cast(ELFsectheader_type, elf.sect[sec.link])
+ break
+ end
+ end
+ return sec_strtab.size, sec_strtab.ofs
+end
+
+local function lua_bin_path(arg)
+ local args_str = require('utils').luacmd(arg)
+ local args = {}
+ for a in args_str:gmatch("%S+") do
+ table.insert(args, a);
+ end
+ return args[1]
+end
+
+test:plan(5)
+
+local elf_filename = os.tmpname() .. '.obj'
+local lua_path = os.getenv('LUA_PATH')
+local lua_bin = lua_bin_path(arg)
+local cmd = ('LUA_PATH="%s" %s -b -n "module_name" -e "print()" %s'):format(lua_path, lua_bin, elf_filename)
+local ret = os.execute(cmd)
+test:ok(ret == 0, 'create an object file')
+
+local elf_content = read_file(elf_filename)
+test:ok(#elf_content ~= 0, 'read an object file')
+local strtab_size, strtab_offset = read_elf_strtab(elf_content)
+test:ok(strtab_size == expected_strtab_size, 'check .strtab size')
+test:ok(strtab_offset == expected_strtab_offset, 'check .strtab offset')
+
+ret = os.execute(("rm -f %s"):format(elf_filename))
+test:ok(ret == 0, 'remove an object file')
+
+os.exit(test:check() and 0 or 1)
--
2.34.1
More information about the Tarantool-patches
mailing list