local elf = require("elf") local ec = require("elf.constants") local function die(fmt, ...) io.stderr:write("mkelf: ", string.format(fmt, ...), "\n") os.exit(1) end local function usage() die("[-o output] [input]") end ---@param fn string|nil ---@return Header, Segments, Sections local function loadconfig(fn) local header, segments, sections = {}, {}, {} local header_mt = { __index = elf.header } local segments_mt = { __index = elf.segment } local sections_mt = { __index = elf.section } local env = { -- Keep in sync with types/elf.d.lua Class = elf.Class, Endian = elf.Endian, Osabi = elf.Osabi, Type = elf.Type, Machine = elf.Machine, SegmentType = elf.SegmentType, SegmentFlags = elf.SegmentFlags, ELFVERSION = elf.VERSION, header = function(t) header = setmetatable(t, header_mt) end, segments = function(t) segments = setmetatable(t, segments_mt) end, sections = function(t) sections = setmetatable(t, sections_mt) end, } -- TODO error check for multiple headers local chunk, err = loadfile(fn, "t", env) if not chunk then die("%s", err) end -- TODO sandbox against malformed configs local ok, perr = pcall(chunk) if not ok then die("%s", perr) end return header, segments, sections end local function main() local outfn, infn = "a.out", nil local i = 1 while arg[i] do if arg[i] == "-o" then i = i + 1 outfn = arg[i] or die("missing filename after -o") elseif infn then usage() else infn = arg[i] end i = i + 1 end local header, segments, sections = loadconfig(infn) header.phnum = #segments header.phentsize = (header.class == ec.Class.bit64) and 0x38 or 0x20 -- TODO write to a temp file and atomic rename to outfn. local out = assert(io.open(outfn, "wb")) out:write(header:pack()) out:write(segments:pack(header.data, header.class)) -- TODO finish section.pack out:write(sections:pack(header.data)) end main()