frexp() is not so hard, even if it is much faster if you have access to the native assembly instructions. In pure C, this could be still implemented with some platform-testing function (using tests on known constants), but you have to use unsafe pointer conversion and be aware of the byte order (endianness).
In practice you can still go faster if you know the CPU and FPU architecture and some of them are now used everywhere : x86, x64/amd64, and arm64 (all the others are older processors or processors for niche markets on embedded systems, many of them using now some arm32 or arm64; there's almost no more use for other x80, x88, 65xx, 68k, Sparc and Mips processors, but there remains now a growing niche with GPUs, mostly from nVdidia and ATI, and for some high-end very costly processors used in supercomputers, and for "virtual processors" running on top of a VM with its own "portable" ABI, including Java, Perl, Lua, or _javascript_).
abort() may seem complex but can be implemented on top of longjmp (and more complete implemention if adding support for signal and raise).
If you compile Lua against a C++ compiler, you can still use the C++ exception handlers to implement setjmp/longjmp in an additional C++ compiled module (but of course you need a C++ compiler like GCC or clang) to declare the needed function with 'extern "C"...' linkage . I bet there are today a C++ compiler available on almost all platforms and they already come with the machinery library to link the few C++ modules with the other C modules or libraries needed by Lua (this is difficult only when you don't have access to the native instruction set and are bound only to a virtual processor, in which case you need to use the VM API, but most VMs have basic support for exception handling or error handling).
The really complex part is if you need to make Lua exist within limits of a multithreading environment, and make manage these limits (notably in memory allocation, time slot, time precision, and permissions).
If you don't have the standard C I/O the program in Lua will still perform I/O with another library (it could be a network API or an IPC mechanism with named channels, using some specific resource allocators, or a database or "registry" service).
One thing that is still missing in Lua is a safe way to integrate it with true (Posix) threads instead of being limited to the "cooperative" model (by which all Lua threads used in a program exist within the same system thread, using the very complex setjmp/longjmp mechanism): we still cannot safely and simply declare to Lua to exist the cooperative model and allow threads to run concurrently, because Lua has no way to coordinate them (it would require the addition of synchronization and serialization, and a definition of event queues, and resource managers: in standard Lua there's a single queue and a single resource manager for everything, the rest is part of the internal integration library but inacessible to Lua programs themselves; this caues huge difficulties to implement efficient networking, notably for implementing services without excessive blocking and without huge variation in response time in a very busy service replying to thousands of queries per second or more, or for interfacing with external database services).
And unlike Java or _javascript_, Lua still has no model for implementing security domains (with efficient resource sharing and data exchanges), and still no clear definition of a basic set of datatypes built for portability (including with known and reproduceable limits): for that you need to add other Lua packages, the basic library is too much limited and too much oriented for basic POSIX C (not much more than the old K&R model but still not enough to even support the POSIX standard). This causes many Lua programs to be non-portable (not even between x86 and x64 architectures, or between ARM32 and ARM64, on the same type of OS like Linux, Windows, or major branches MacOS/iOS).
So Lua is basically a language defined by its syntax, it still has no formal API (let's put aside the ABI or its implementing VM): it works, yes, but the results are not reproductible, so Lua-written software is difficult to test: you need to develop Lua programs as well as test programs at the same time to target each platform and check the dependencies. There's no test framework like in Java, Perl or _javascript_, not even for basic conformance level: you cannot develop on a system and deploy to others easily: you need to test/debug against each platform and there's nothing in Lua that allows asserting that a Lua module is compatible with some known platform type, no versioning system; each Lua implementation is very tightly linked to its initial platform (including the current "standard" Lua), and this also applies to its documentation: you need to tweak also this documentation to specify the limits and target platforms on which it was tested.
Lua is still now is in the same "infant" stage as what was "K&R" C in the 1980's (unfortunately it remained too long in that stage and caused a proliferation of ABI's and later huge complexity to write portable C programs; the same risk exists now for Lua). May be there will be a change later when there will be a version of the language sponsored by a good standard body (ISO, IEEE, ECMA, ANSI...) and its development will be open (and Lua will not just be "opensource" as of today). Or when its development will be open to more members (e.g. the Mozilla, Linux, GNU foundations) and with formal process (but it will introduce bureaucracy and costs and possibly tensions between members like those for Java or C++ today). The costs would be supported by large service providers and sellers offering services in Lua but they may influence the future design of the language.