Monthly Archives: October 2014

Building Lua with ELLCC This Time With a Twist

In a previous post, I used ELLCC to cross build Lua for the ARM running Linux. Subsequently I’ve done a bit of work to make ELLCC more configurable, and also to handle bare metal compilation more easily. I had a little time on my hands tonight so I thought I’d try out the changes with the latest Lua 5.2.3 version.
First, I modified the lua-5.2.3/src/Makefile to add the following around line 27:

# Start of ELLCC definitions.
PLAT= generic
ELLCC= /home/rich/ellcc
ELLCCBIN= $(ELLCC)/bin/
CC= $(ELLCCBIN)ecc
ELLCCPREFIX= $(ELLCCBIN)ecc-
AR= $(ELLCCPREFIX)ar rcu
RANLIB= $(ELLCCPREFIX)ranlib

TARGET= x86_64-linux-eng
MYCFLAGS= -target $(TARGET)
MYLDFLAGS= -target $(TARGET)
# End of ELLCC definitions.

Then I build for my host system, an x86_64 Linux box:

[~/lua-5.2.3/src] dev% make
/home/rich/ellcc/bin/ecc -O2 -Wall -DLUA_COMPAT_ALL  -target x86_64-linux-eng   -c -o lapi.o lapi.c
...
/home/rich/ellcc/bin/ecc -O2 -Wall -DLUA_COMPAT_ALL  -target x86_64-linux-eng   -c -o linit.o linit.c
/home/rich/ellcc/bin/ecc-ar rcu liblua.a lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o 
/home/rich/ellcc/bin/ecc-ranlib liblua.a
/home/rich/ellcc/bin/ecc -O2 -Wall -DLUA_COMPAT_ALL  -target x86_64-linux-eng   -c -o lua.o lua.c
/home/rich/ellcc/bin/ecc -o lua  -target x86_64-linux-eng lua.o liblua.a -lm  
/home/rich/ellcc/bin/ecc -O2 -Wall -DLUA_COMPAT_ALL  -target x86_64-linux-eng   -c -o luac.o luac.c
/home/rich/ellcc/bin/ecc -o luac  -target x86_64-linux-eng luac.o liblua.a -lm  
[~/lua-5.2.3/src] dev% ./lua
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> print ("hello")
hello
> 
[~/lua-5.2.3/src] dev% 

So far so good. How about a cross compile?

[~/lua-5.2.3/src] dev% make clean
rm -f liblua.a lua luac lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o lmathlib.o loslib.o lstrlib.o ltablib.o loadlib.o linit.o  lua.o luac.o
[~/lua-5.2.3/src] dev% make TARGET=arm-linux-engeabi
/home/rich/ellcc/bin/ecc -O2 -Wall -DLUA_COMPAT_ALL  -target arm-linux-engeabi   -c -o lapi.o lapi.c
...
/home/rich/ellcc/bin/ecc -o lua  -target arm-linux-engeabi lua.o liblua.a -lm  
/home/rich/ellcc/bin/ecc -O2 -Wall -DLUA_COMPAT_ALL  -target arm-linux-engeabi   -c -o luac.o luac.c
/home/rich/ellcc/bin/ecc -o luac  -target arm-linux-engeabi luac.o liblua.a -lm  
[~/lua-5.2.3/src] dev% ~/ellcc/bin/qemu-arm lua
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> print ("hello")
hello
> 
[~/lua-5.2.3/src] dev% 

Now for a real test. How about a bare metal test on the ARM?

[~/lua-5.2.3/src] dev% rm lua
[~/lua-5.2.3/src] dev% make TARGET=arm-elk-engeabi
/home/rich/ellcc/bin/ecc -o lua  -target arm-elk-engeabi lua.o liblua.a -lm  
[~/lua-5.2.3/src] dev%  ~/ellcc/bin/qemu-system-arm -M vexpress-a9 -m 128M -nographic -kernel lua
audio: Could not init `oss' audio driver
unhandled system call (256) args: 1, 268472376, 1610613215, 1610613023, 1207961673, 1241513744
Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> print ("hello")
unhandled system call (175) args: 1, 1241512616, 0, 8, 237792, 0
unhandled system call (174) args: 2, 1241512644, 1241512624, 8, 237792, 0
hello
unhandled system call (174) args: 2, 1241512644, 1241512624, 8, 237792, 0
> 

As described in the previous post, the unhandled system calls are those that haven’t been implemented in ELK yet. In this case, they are

...
#define __NR_rt_sigaction       174
#define __NR_rt_sigprocmask     175
...
#define __NR_set_tid_address    256
...

none of which are needed in my little test. Bare metal Lua. Luanix?

After I had this little bit of excitement, I remembered that I had configured ELK with the task scheduler and system timer. I figured it might be worth a try to see if at least the interrupt driven timer was working. Sure enough:

> print (os.date())
unhandled system call (174) args: 2, 1241512644, 1241512624, 8, 1207961832, 1241512696
unhandled system call (5) args: 276151, 657408, 0, 1, 1241510728, 1241511520
Thu Jan  1 00:07:22 1970
unhandled system call (174) args: 2, 1241512644, 1241512624, 8, 1207961832, 1241512696
> print (os.date())
unhandled system call (174) args: 2, 1241512644, 1241512624, 8, 1207961832, 1241512696
Thu Jan  1 00:07:45 1970
unhandled system call (174) args: 2, 1241512644, 1241512624, 8, 1207961832, 1241512696
> 

Time keeps on ticking. Fun stuff.

ELLCC Now Available for Windows

Last week someone mentioned that he’d like to run the ELLCC cross development tools on an operating system called “Windows”. Doing a little goolging proved that he might not be alone. Windows seems to be fairly popular, rivaling even Linux in popularity on the desktop. I decided to see what it would take to get ELLCC running on Windows. I spent the day Saturday installing MinGW-w64 on my development system and tweaking the ELLCC build rules to use it. The result is that I can now make a binary snapshot of ELLCC that runs on Windows which I have placed on the ftp site at ftp://ellcc.org/pub.

Here is an example of the results:

C:\cygwin\home\rich>ellcc\bin\ecc.exe -target x86_64-linux-eng hello.c

C:\cygwin\home\rich>ellcc\bin\ecc-size a.out
   text    data     bss     dec     hex filename
  15595     248    1608   17451    442b a.out

C:\cygwin\home\rich>

If I copy a.out to my Linux box, I get:

[~] dev% ellcc/bin/ecc-size a.out
   text    data     bss     dec     hex filename
  15595     248    1608   17451    442b a.out 
[~] dev% ./a.out 
hello world
[~] dev%

You can also use the work-in-progress ELK bare metal environment:

C:\cygwin\home\rich>ellcc\bin\ecc.exe -target arm-elk-engeabi hello.c -g

C:\cygwin\home\rich>ellcc\bin\ecc-size.exe a.out
   text    data     bss     dec     hex filename
  76923    2744   23096  102763   1916b a.out

C:\cygwin\home\rich>

If you have QEMU installed on your Windows box, you can run the bare metal executable as described in a previous blog post.

This makes it theoretically possible for me to do further development of ELLCC on Windows. I don’t think I will though.

Introducing ELK: A Bare Metal Environment for ELLCC

ELLCC (pronounced “elk”) is a C/C++ programming environment based on the clang/LLVM compiler. The goal of ELLCC is to provide a complete tool chain and run-time environment for developing C/C++ programs for embedded systems. ELLCC supports several Linux targets today, specifically ARM, Mips, PowerPC, and x86 systems. ELK (which might mean “embedded little kernel” or “embedded Linux kernel”) is a work-in-progress that allows the ELLCC tool chain to target bare metal environments where an OS is not available or needed.

What will differentiate ELK from other bare metal environments is that the goal is to provide a fairly complete Linux-like environment without the need for actually running Linux. ELK is in the design and development stage right now, but the basic functionality has been implemented based on work done using ELLCC for bare metal development and making the ELLCC tool chain easily configurable.

The thing that makes ELK fairly unique is that it uses the C and C++ libraries compiled for Linux. It does this by handling Linux system calls using the normal system call mechanism for each target. ELK has extensible system call handling capability so that new system call emulators can be added as needed. ELK is being developed by setting up the infrastructure for program start up in the bare metal environment and handling system calls and context switching in a small assembly language file. A fairly functional example for ARM can be seen here. System call support can be added easily. Here is a simple exit() system call example:

/* Handle the exit system call.
 */     
#include <bits/syscall.h>       // For syscall numbers.
#include <stdio.h>
#include <kernel.h>

// Make the simple console a loadable feature.
FEATURE(exit, exit)

static int sys_exit(int status)
{
    printf("The program has exited.\n");
    for( ;; )
      continue;
}       
        
CONSTRUCTOR()   
{       
    // Set up a simple exit system call.
    __set_syscall(SYS_exit, sys_exit);
}       

Here’s an example of a simple ARM program running on QEMU in system (bare metal) mode:

[~] dev% cat hello.cpp
#include <iostream>

int main()
{
  std::cout << "hello world" << std::endl;
}
[~] dev% ~/ellcc/bin/ecc++ -target arm-elk-engeabi hello.cpp -g
[~] dev% ~/ellcc/bin/qemu-system-arm -M vexpress-a9 -m 128M -nographic -kernel a.out
audio: Could not init `oss' audio driver
unhandled system call (256) args: 1, 268472376, 1610613215, 1610613023, 1207961673, 1241513736
unhandled system call (45) args: 0, 0, 0, 1241512408, 590752, 0
unhandled system call (45) args: 4096, 4111, 1241512408, 1241512336, 592800, 1254352
unhandled system call (192) args: 0, 8192, 3, 34, -1, 0
unhandled system call (45) args: 4096, 4111, 34, 1241512336, 592800, -1
unhandled system call (192) args: 0, 8192, 3, 34, -1, 0
hello world
unhandled system call (248) args: 0, 1207962904, 1309668, 0, 1207991180, 1241513736
The program has exited.

Notice that there are several unhandled system calls (I did say that ELK is a work-in-progress) but enough has been implemented that “hello world” comes out.
The C version is a little quieter:

[~] dev% ~/ellcc/bin/qemu-system-arm -M vexpress-a9 -m 128M -nographic -kernel a.out
audio: Could not init `oss' audio driver
unhandled system call (256) args: 1, 268472376, 1610613215, 1610613023, 1207961673, 1241513736
hello world
unhandled system call (248) args: 0, 0, 1207983756, 0, 1207985256, 1241513736
The program has exited.

The current state of ELK is that only the ARM version is at all functional. It supports multiple threads, memory allocation using malloc, semaphores, and timers. ELK started out as a couple of prototypes to test the feasibility of using Linux libraries on bare metal and to enhance the ability to configure the tool chain for multiple environments. I like the way that the development is going so far and hope to have a complete ARM implementation soon and support for the other targets soon after that. You can browse the complete source code for ELK.