From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 1684946B100; Mon, 22 May 2023 12:35:16 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 1684946B100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1684748116; bh=bHzkIFAVWV2oiFOgI3kdF5+QeoFZv82wTfBqcTtf8yQ=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=wfpOBhIozmYh3WSpSF9Hrs19jzTyKk8y4wKzp1qYSeUG1weBOoMtsbwGJktZIaMxp F3ZAQbCJQxYUxnNj83wzZUUd49MMoe7qQEU3GAVbEwQYcdE4O0u/afP1GG99Zddjid zKo6XhKHtkgySQ8Mydbp5jqnfZ6JGuqEZ79tkZF8= Received: from mail-ed1-f51.google.com (mail-ed1-f51.google.com [209.85.208.51]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 4AD8746A527 for ; Mon, 22 May 2023 12:35:15 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 4AD8746A527 Received: by mail-ed1-f51.google.com with SMTP id 4fb4d7f45d1cf-510ddeab704so7546268a12.3 for ; Mon, 22 May 2023 02:35:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684748114; x=1687340114; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=QEhsiUKocicvXQTa2+aG691H9pjipEXFgPgKfjfIqCc=; b=CvOHlxK8FqXkHN1oUL/7Zpvt7KDJEW++fl5S0qqevE7YaYpMYedhZkDmF6ArAAJ8v7 YkuA79r8usDxfCQg6HR7+wN1iLaPttnVAXai1i3FkTQBZ4A5x4EFiamoMZLvyHpUSuPk 8RvL5PJhrDbIHJOuxdaJu1v6A+RE1pit96Mm0XyGASFXjHF1I9iNiYS113dUIOFJaWBR 9ygu6i4xImUhNUUrW+X6QSfz3n/7+tHTOb5Sh75OTUjH7ti1/sNmhJeUUbCbFmKDYlhx NfW6SjJTq9PhWY7c7ujNTTcyWTka1wSG/1VpWNWp5Ctkf8lxyZ0wctqPBuyhSG1wS3wE Gabg== X-Gm-Message-State: AC+VfDwFU0Dp+fqWFM7NSBALHSyXeFPTEugIacCR84Api7omZJiHQgJ3 5vOTxk0iuYPOVdFRK2e0qtknRUJ7j/XEQA== X-Google-Smtp-Source: ACHHUZ4Xrz23JC0lS6rUOFQlECcHw3WJ5ZBYBUa3P2Q0hl9b1yru/HkS3mputlWr+WW91iqD3jUT8Q== X-Received: by 2002:a17:907:3e9d:b0:970:d43:7fd1 with SMTP id hs29-20020a1709073e9d00b009700d437fd1mr718649ejc.52.1684748113780; Mon, 22 May 2023 02:35:13 -0700 (PDT) Received: from pony.. ([185.6.247.97]) by smtp.gmail.com with ESMTPSA id md21-20020a170906ae9500b009661afd3b86sm2902954ejb.171.2023.05.22.02.35.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 May 2023 02:35:13 -0700 (PDT) To: tarantool-patches@dev.tarantool.org Date: Mon, 22 May 2023 11:58:05 +0300 Message-Id: X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH] Fix saved bytecode encapsulated in ELF objects. X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" From: Sergey Bronnikov 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 --- 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