[HN Gopher] A standalone zero-dependency Lisp for Linux
       ___________________________________________________________________
        
       A standalone zero-dependency Lisp for Linux
        
       Author : keepamovin
       Score  : 112 points
       Date   : 2023-11-03 08:44 UTC (3 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | nerdponx wrote:
       | > Lone is a freestanding Lisp interpreter designed to run
       | directly on top of the Linux kernel with full support for Linux
       | system calls. It has zero dependencies, not even the C standard
       | library.
       | 
       | Cool project! Not sure if I'm going to start using it any time
       | soon, but cool nonetheless.
        
         | matheusmoreira wrote:
         | Thank you!
        
       | ashton314 wrote:
       | Very cool! In a similar vein there's Zuo:
       | https://github.com/racket/zuo
        
         | nerdponx wrote:
         | Zuo is interesting because (as far as I know) its primary user
         | is the Racket project itself, for bootstrapping the compiler.
        
           | ashton314 wrote:
           | That is correct
        
       | ape4 wrote:
       | A quick glance shows it uses GNU Make but that's only a build
       | time dependency, I guess.
        
         | yjftsjthsd-h wrote:
         | All software needs dependencies at build time, saying no
         | dependencies always means runtime.
        
           | blueflow wrote:
           | I'm surprised the Kernel doesn't count here.
        
             | yjftsjthsd-h wrote:
             | At that point we really get into semantics... But now that
             | you mention it, I would be interested to see if it could be
             | built with APE to benefit from their bare metal support.
        
             | rollcat wrote:
             | It does.
             | 
             | Writing your software to directly use the syscalls of a
             | specific kernel does not make it "zero dependency", it
             | makes it "one dependency" - and non-portable.
             | 
             | The author elaborates on their rationale and the technical
             | details in a blog post:
             | <https://www.matheusmoreira.com/articles/linux-system-
             | calls>
             | 
             | TBH I have mixed feelings about this approach. It's true
             | that this is more or less what Go or (Cosmopolitan libc)
             | do, but the motivation in their case is to maximize
             | portability (by making cross-compilation trivial). However
             | when you #include <linux/...>, you not only make your
             | software non-portable, you also make it a PITA to cross-
             | compile as you need the kernel headers on the host machine.
             | 
             | In contrast, with Go or cosmo, I can trivially build a tiny
             | /sbin/init for amd64 Linux, pack it up with cpio, and run
             | it with qemu-system-x86_64 -initrd - all from a Mac/arm64
             | host.
        
               | craftkiller wrote:
               | Surely its more than one dependency. For example, you'll
               | need a processor. Not just any processor, but a processor
               | for which a C compiler has been written.
        
               | matheusmoreira wrote:
               | That's a _great_ question... I wonder if Justine would be
               | interested in that. She has her own sector lisp too.
        
               | matheusmoreira wrote:
               | > However when you #include <linux/...>, you not only
               | make your software non-portable, you also make it a PITA
               | to cross-compile as you need the kernel headers on the
               | host machine.
               | 
               | Yes, that is certainly a problem that I need to solve.
               | 
               | I added some support for cross compilation in the
               | makefile. It currently requires clang for that.
               | ifdef TARGET         ifndef UAPI           $(error UAPI
               | must be defined when cross compiling)         endif
               | TARGET.triple := $(TARGET)-unknown-linux-elf
               | override CC := clang -target $(TARGET.triple)       else
               | TARGET := $(shell uname -m)       endif
               | 
               | With this, I was able to cross compile lone for x86_64
               | from within the Termux environment of my aarch64
               | smartphone. All I had to do was obtain the Linux user
               | space API headers for x86_64. Getting those headers was
               | somewhat annoying but doable, there are packages for them
               | in many Linux distributions.
               | 
               | I made a Termux package request for multiplatform Linux
               | UAPI headers specifically so I could cross compile lone
               | but unfortunately it was rejected.
               | 
               | https://github.com/termux/termux-packages/issues/16069
        
         | matheusmoreira wrote:
         | Yes. It has zero runtime dependencies but development currently
         | assumes GNU tools. The test suite for example is entirely
         | written in bash and uses GNU coreutils. I submitted a patch to
         | coreutils to allow env to set argv[0] of programs specifically
         | so I could use it in my test suite.
         | 
         | Currently lone is a single C source file. It could easily be
         | compiled manually if necessary. I've started reorganizing the
         | repository though so that's likely to change.
        
       | nanolith wrote:
       | This is interesting. Although, I think it's always useful to
       | point out that runtimes that directly make system calls will have
       | portability issues in other *nix systems. For instance, OpenBSD
       | has recently restricted system calls to a single offset of their
       | libc in order to reduce ROP attacks.
       | 
       | If Lone wishes to be portable, it will need to consider a libc
       | dependency as an option. If not, it can probably get away with
       | direct syscalls on Linux unless Linux kernel developers decide to
       | add support for pinning system calls. I doubt that this would
       | ever be a hard requirement in the kernel, as it would break
       | userland all over, but I could see this being an option for
       | certain distributions as a ROP mitigation. Many features like
       | these flow from OpenBSD to other OSes.
        
         | edgyquant wrote:
         | Considering the title and use case it seems to be intentionally
         | pretty specific to Linux
        
           | nanolith wrote:
           | Many projects start this way. But, as per my comment, the
           | assumption that direct syscall support will be maintained in
           | future Linux distros is also risky.
        
             | matheusmoreira wrote:
             | I worry about that risk as well. I assume that even if
             | Linux were to introduce a mechanism for system call
             | authentication, it would be something lone would be able to
             | use to mark its system call primitive as allowed.
        
               | nanolith wrote:
               | Perhaps. To be fair, I'm not aware of anything on the
               | horizon, other than the fact that OpenBSD has been
               | showing off their pinning implementation.
               | 
               | As long as you know it's a possibility, then the point of
               | my original comment is met.
               | 
               | Good luck on this project. I look forward to seeing it
               | progress.
        
               | matheusmoreira wrote:
               | Thank you!
        
             | kwhitefoot wrote:
             | Why is it risky? Linus is adamant that the greatest sin is
             | breaking userland.
        
         | Conscat wrote:
         | I think this decision from OpenBSD will more likely discourage
         | developers from even considering it a supportable platform for
         | software that originates in Linux land.
        
           | nanolith wrote:
           | Direct syscall access is not something that is guaranteed in
           | Unix derivatives. Linux is rare in that it provides a stable
           | syscall API. Source compatibility is often only guaranteed
           | when linked against libc or an equivalent low-level runtime
           | library.
        
             | eikenberry wrote:
             | And this is generally a bad pattern unless those libc
             | equivalents are services you call (like syscalls) and not a
             | library you have to import or FFI. Requiring importing a
             | library, probably from another language, is not a good
             | alternative to syscalls.
        
               | nanolith wrote:
               | A bad pattern according to whom? Most language runtime
               | libraries import other system libraries as needed. For
               | better or for worse, libc is typically considered to be a
               | system library. It's something that every distribution or
               | Unix flavor provides that is guaranteed to work within
               | the POSIX standard for interfacing with the operating
               | system. It's up to the distribution maintainers to make
               | that happen, even if they tweak things to support syscall
               | pinning or seccomp rules.
               | 
               | Userland directly calling a stable syscall API is a rare
               | thing outside of Linux, and there is no guarantee that it
               | will last forever even in Linux given the latest attacks.
               | With modern ROP mitigations like syscall pinning, it will
               | in fact be more dangerous to make syscalls directly -- if
               | allowed in your distribution -- than it would be to call
               | the minimal footprint of libc required to bootstrap a
               | high level language runtime.
               | 
               | Of course, with special pleading, it could be possible
               | for distribution or OS maintainers to carve out an
               | exception for syscall pinning for a particular language
               | runtime. Ask Go how that's going for their OpenBSD port.
        
               | eikenberry wrote:
               | The problem with system libraries requiring importing
               | them as C libraries isn't new and doesn't seem to be
               | going away. It has caused all sorts of problems for
               | alternative languages over the years that it seems like
               | an alternative would give all of computing a giant boost
               | by allowing different models that don't work well with C.
               | Stabilizing and standardizing the syscall interfaces
               | would be one way to accomplish this and is the closest
               | thing we have to it now. Implementing syscalls as a
               | separate service might also work but then you have the
               | IPC overhead. That might not be as bad though as we'll
               | end up with something like that anyways as requirements
               | ramp up for C to have it's own runtime (eg.
               | https://dslab.epfl.ch/research/cpi/).
        
               | dontlaugh wrote:
               | No, it's fine. And common, macOS and Windows do the same.
        
               | baq wrote:
               | To be fair, linking to kernel32 is a bit different than
               | linking to msvcrt, but yeah, it's Linux who's the
               | slightly insane person in the room, not the other way
               | around.
        
               | dontlaugh wrote:
               | I wouldn't say insane exactly, but definitely overly
               | restrictive.
        
         | matheusmoreira wrote:
         | You're absolutely right, it is not portable to other operating
         | systems. I have written about this portability and system call
         | stability here on HN a few times, at some point I decided to
         | compile all the information into a post on my website.
         | 
         | https://www.matheusmoreira.com/articles/linux-system-calls
         | 
         | I started lone (and previously a liblinux library) in order to
         | make applications directly targeting the Linux system call
         | binary interface. I chose Linux precisely because it's the only
         | one with a stable interface.
         | 
         | I currently have no plans to make lone a portable programming
         | language.
        
       | netbioserror wrote:
       | So I guess the difference from Janet is no C standard library
       | dependency; is this being targeted for hyper-slim and embedded
       | uses? Because Janet seems like a good choice for most desktop and
       | server cases.
        
         | matheusmoreira wrote:
         | Yes. My current goal is to boot Linux directly into Lisp and
         | bring up the rest of the system from there. Perhaps even create
         | a Lisp user space.
        
           | FredPret wrote:
           | I'm new to Lisp - would this then be a modern Lisp machine?
        
             | f1shy wrote:
             | Well, if by lisp machine we understand a processor that can
             | run native lisp, of course not, but I was dreaming with a
             | modern lisp machine, and this is the best that can be
             | practically made
        
             | matheusmoreira wrote:
             | It's certainly what I had in mind when I started the
             | project. Writing a full Lisp operating system is extremely
             | hard, better to take advantage of Linux and its drivers so
             | as to avoid spending an entire lifetime recreating them.
             | 
             | It's my understanding that a true Lisp machine would have
             | hardware support for Lisp abstractions at the instruction
             | set level, so I don't think the concept would apply to
             | lone. I would be seriously honored if people considered it
             | one though, even if only in spirit.
        
       | matheusmoreira wrote:
       | Hello everyone! I started this project, happy to answer any
       | questions.
       | 
       | I was hoping to polish it up a bit more so it would be worthy of
       | a Show HN, never thought someone else would submit it here.
       | Really made my day!
        
       | rcarmo wrote:
       | Nice. I can see something like this being used with circle
       | (https://github.com/rsta2/circle) to run bare metal on a Pi, too.
        
       | gigatexal wrote:
       | Very cool project. Not commenting on that. Lisp and it's
       | derivatives often hits the front page of HN and I always wonder
       | why. What is it about lisp that is so powerful? so much so that
       | some see it as the platonic ideal of programming languages or so
       | it seems?
        
         | packetslave wrote:
         | It doesn't hurt that HN is written in LISP.
        
         | f1shy wrote:
         | Well, Y combinator, the domain of HN is intimately related to
         | Lisp, as the founder Paul Graham. That is how I landed in this
         | site to begin, and I assume is so for many around. That could
         | explain it a little bit.
        
         | barbazoo wrote:
         | > Ask HN: Why is everyone here so obsessed with Lisp?
         | 
         | https://news.ycombinator.com/item?id=20697493
        
           | gigatexal wrote:
           | Ahh okay. Paul Graham and the hackability of the language
           | itself. Got it.
        
       | jng wrote:
       | Beautiful. Also, after 30+ years of writing C and C++, I learned
       | one thing by casually browsing the source code: you can use a
       | preprocessor macro in an #include statement. Thanks.
        
         | matheusmoreira wrote:
         | Yes! GCC calls it computed includes.
         | 
         | https://gcc.gnu.org/onlinedocs/cpp/Computed-Includes.html
         | 
         | I used it to include architecture-specific source code and also
         | a generated C file containing a table of Linux system calls
         | defined by the Linux UAPI lone is compiled against.
        
       ___________________________________________________________________
       (page generated 2023-11-06 21:00 UTC)