Tag Archives: Apps

Building NetBSD Userland with ELLCC.

I’ve started a new project to build the core NetBSD userland programs for Linux using ELLCC. I have two motivations for doing this:

  • To have a large set of programs to compile for testing ELLCC. I’ve been looking for something for a while, and my stackoverflow question didn’t come up with any responses.
  • I’d like to eventually have a full set of userland commands for Linux that are not GPL licensed.

So far, the results have been promising. I have a nice subset of the NetBSD userland compiled so far:

ls x86_64-linux/bin x86_64-linux/usr/bin
x86_64-linux/bin:
[*      cp*    domainname*  expr*      ksh*  mkdir*  pwd*    sh*     tar*
cat*    cpio*  echo*        hostname*  ln*   mv*     rm*     sleep*  test*
chmod*  date*  ed*          kill*      ls*   pax*    rmdir*  sync*

x86_64-linux/usr/bin:
apply*     calendar*  crunchgen*  expand*  getconf*  lastcomm*  make*
asa*       checknr*   crunchide*  fgen*    getopt*   leave*     od*
at*        cmp*       csplit*     find*    groups*   locate*    tar@
atq*       col*       ctags*      flock*   head*     lock*      uncompress*
atrm*      colcrt*    cut*        fmt*     hexdump*  logname*   whoami*
banner*    colrm*     deroff*     fold*    id*       look*
basename*  column*    dirname*    fpr*     indent*   m4*
batch*     comm*      du*         from*    join*     mail*
biff*      compress*  env*        fsplit*  jot*      Mail*
cal*       cpio@      error*      ftp*     lam*      mailx*
[~/ellcc-bsd] dev%

The files in that listing represent the low hanging fruit: They are the files that required little or no editing to compile with ELLCC.

If you want to try to build the NetBSD userland using ELLCC, first install ELLCC itself. Then you can grab the current ellcc-bsd project files:

[~] dev% svn co http://ellcc.org/svn/ellcc-bsd/trunk ellcc-bsd

This will create the ellcc-bsd directory right next to the already existing ellcc directory.

The next step is to build the bmake program (the Berkeley make program, used by NetBSD):

[~] dev% cd ellcc-bsd/
[~/ellcc-bsd] dev% ./build

This will put the host bmake executable in the ~/ellcc/bin directory.

Now all you have to do is

[~/ellcc-bsd] dev% ~/ellcc/bin/bmake
...
[~/ellcc-bsd] dev% ~/ellcc/bin/bmake install

This will create the populated directories list above.

For a little more fun try building ARM executables:

[~/ellcc-bsd] dev% ~/ellcc/bin/bmake TARGET=arm
...
[~/ellcc-bsd] dev% ~/ellcc/bin/bmake TARGET=arm install
...
[~/ellcc-bsd] dev% ls arm-linux/bin/ arm-linux/usr/bin/
arm-linux/bin/:
[*      cp*    domainname*  expr*      ksh*  mkdir*  pwd*    sh*     tar*
cat*    cpio*  echo*        hostname*  ln*   mv*     rm*     sleep*  test*
chmod*  date*  ed*          kill*      ls*   pax*    rmdir*  sync*

arm-linux/usr/bin/:
apply*      csplit*   hexdump*   mkstr*         sdiff*       uniq*
asa*        ctags*    id*        mktemp*        sed*         units*
at*         cut*      indent*    mkubootimage*  seq*         unvis*
atq*        deroff*   join*      msgc*          shlock*      users*
atrm*       dirname*  jot*       msgs*          shuffle*     uudecode*
banner*     du*       lam*       nbperf*        soelim*      uuencode*
basename*   env*      lastcomm*  newgrp*        sort*        uuidgen*
batch*      error*    leave*     newsyslog*     split*       vis*
biff*       expand*   locate*    nice*          stat*        wall*
cal*        fgen*     lock*      nl*            su*          wc*
calendar*   find*     logname*   nohup*         tabs*        what*
checknr*    flock*    look*      od*            tar@         whereis*
cmp*        fmt*      m4*        paste*         tee*         which*
col*        fold*     mail*      patch*         time*        who*
colcrt*     fpr*      Mail*      pathchk*       touch*       whoami*
colrm*      from*     mailx*     pr*            tr*          whois*
column*     fsplit*   make*      printenv*      tty*         window*
comm*       ftp*      man*       printf*        ul*          write*
compress*   getconf*  menuc*     progress*      uname*       xargs*
cpio@       getopt*   mesg*      readlink*      uncompress*  xstr*
crunchgen*  groups*   mkdep*     renice*        unexpand*    yes*
crunchide*  head*     mkfifo*    rs*            unifdef*
[~/ellcc-bsd] dev% file arm-linux/bin/sh
arm-linux/bin/sh: ELF 32-bit LSB executable, ARM, version 1, statically linked, BuildID[sha1]=2a1b11acf02098cd6b77965f97d3e4031126951e, stripped
[~/ellcc-bsd] dev%

In a future post I’ll describe how to use chroot to play in the new tiny userland environment.

Cross Building tcsh with ELLCC

Now that ELLCC can build itself, it’s time to do some testing of other packages. I thought tcsh (a widely used command shell for *nix) would be a good choice, because it would exercise a bunch of system calls and standard library functions on all the targets.

I created a tcsh directory under the ELLCC test/src directory and got the latest version of tcsh sources.

I made a modified build script and Makefile to do the overall configure and build because I wanted an easy way to create executables for all the targets. The build script creates a directory for each target and runs the tcsh configure program in the directory:

#!/bin/sh
# ELLCC build script.

# Get the staging directory.
prefix=`cd ../../..; pwd`

# Figure out the compilers to use.
. $prefix/build-setup $*

echo Configured to $WHY.
echo C compiler: $cc $CFLAGS
echo C++ compiler: $cxx $CXXFLAGS
echo In: build$builddir

if [ "x$arg1" != "x" ] ; then
    # Build for a single target.
    targets=$arg1
fi

# Configure for all active targets in the target list.
for t in $targets; do
  t=`basename $t -elf`
  if [ -e $prefix/libecc/mkscripts/targets/$t/setup.mk ] ; then
    echo Configuring for $t-$os
    mkdir -p build-$t-$os
    make DIR=build-$t-$os CC=$cc CXX=$cxx AR=$ar TARGET=$t OS=$os \
        target=$t haslibs=$haslibs \
        bindir=$bindir prefix=$prefix build=$build \
        configure || exit 1

    make -C build-$t-$os || exit 1
  fi
done

The build script uses a simple make file to get the proper build parameters for each target:

-include $(prefix)/libecc/mkscripts/targets/$(TARGET)/setup.mk

ifneq ($(TARGET),$(build))
  HOST=--host=$(TARGET)-$(OS)
  BUILD=--build=$(build)-$(OS)
else
  HOST=
  BUILD=
endif

ifneq ($(CC),gcc)
  ifeq ($(haslibs),yes)
    CFLAGS=$(CFLAGS.$(TARGET))
    CXXFLAGS=$(CXXFLAGS.$(TARGET))
  endif
endif

configure:
        cd $(DIR) ; \
        ../src/configure \
        CC=$(CC) CFLAGS="$(CFLAGS)" \
        CXX=$(CXX) CXXFLAGS="$(CXXFLAGS)" \
        --bindir=$(bindir) --prefix=$(prefix) \
        $(HOST) $(BUILD) $(TARGETS)

clean:
        rm -fr build-*

Now building is a simple as:

[~/ellcc/test/src/tcsh] dev% ./build

This will do all the configures and makes. The file command can tell what each binary is:

[~/ellcc/test/src/tcsh] dev% file */tcsh
build-armeb-linux/tcsh:      ELF 32-bit MSB executable, ARM, version 1, statically linked, BuildID[sha1]=0x078219cbae606a2a0f587d2ef1ec08cb2f74507d, not stripped
build-arm-linux/tcsh:        ELF 32-bit LSB executable, ARM, version 1, statically linked, BuildID[sha1]=0x1e9b7097aeabe9d87bab6a6c58299d5e9ad8420b, not stripped
build-i386-linux/tcsh:       ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, BuildID[sha1]=0xe22f2010af0036439a4291a813fe52281fc0a854, not stripped
build-microblaze-linux/tcsh: ELF 32-bit MSB executable, version 1 (SYSV), statically linked, not stripped
build-mipsel-linux/tcsh:     ELF 32-bit LSB executable, MIPS, MIPS-I version 1, statically linked, BuildID[sha1]=0x38cea1a3ab4fbc8499d49c9db3d81fb61856694d, not stripped
build-mips-linux/tcsh:       ELF 32-bit MSB executable, MIPS, MIPS-I version 1, statically linked, BuildID[sha1]=0xfb15ef6c9556283827968236f14b182f23ecc1e0, not stripped
build-ppc-linux/tcsh:        ELF 32-bit MSB executable, PowerPC or cisco 4500, version 1 (SYSV), statically linked, BuildID[sha1]=0x728ba20e60011cb9e4daff2961c285fa689e23aa, not stripped
build-x86_64-linux/tcsh:     ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=0xbd05c401b4275cb101304547a070d55dd296227c, not stripped
[~/ellcc/test/src/tcsh] dev%

The size command will give a comparison of the executable size of each target:

[~/ellcc/test/src/tcsh] dev% size */tcsh
   text    data     bss     dec     hex filename
 852268   11940   84232  948440   e78d8 build-armeb-linux/tcsh
 850044   11940   84232  946216   e7028 build-arm-linux/tcsh
 836222   11932   83960  932114   e3912 build-i386-linux/tcsh
1211936   11944   84104 1307984  13f550 build-microblaze-linux/tcsh
 963356   11984   84088 1059428  102a64 build-mipsel-linux/tcsh
 963536   11984   84088 1059608  102b18 build-mips-linux/tcsh
 892092   13364   84352  989808   f1a70 build-ppc-linux/tcsh
 878438   15800   89840  984078   f040e build-x86_64-linux/tcsh
[~/ellcc/test/src/tcsh] dev%

It is interesting that the microblaze text section is to much larger than the rest.

I’ll try to run one of the executables.

[~/ellcc/test/src/tcsh] dev% ~/ellcc/bin/qemu-ppc build-ppc-linux/tcsh
[~/ellcc/test/src/tcsh] dev% echo $version
tcsh 6.18.01 (Astron) 2012-02-14 (ppc-apple-linux) options wide,nls,dl,al,kan,rh,color,filec
[~/ellcc/test/src/tcsh] dev%

Sure enough, it is an ppc-apple-linux build (!?!). Fun.

Building Lua for ARM with ELLCC

Today someone mentioned Lua the scripting language and how it was a nice embed-able language well suited to small embedded systems. I decided to see how well ELLCC could do building Lua for an ARM Linux target. You can build the ELLCC compiler package by following the instructions here.

I downloaded the latest Lua tarball from their download page and was off to the races. I extracted Lua into my ~/ellcc directory:

[~] dev% cd ~/ellcc
[~/ellcc] dev% tar xvfpz Downloads/lua-5.2.2.tar.gz

I made a few small changes to their configuration to use ecc for the ARM:

[~] dev% diff -r -c lua-5.2.2 ellcc/lua-5.2.2/
diff -r -c lua-5.2.2/src/luaconf.h ellcc/lua-5.2.2/src/luaconf.h
*** lua-5.2.2/src/luaconf.h     2013-03-16 16:10:18.000000000 -0500
--- ellcc/lua-5.2.2/src/luaconf.h       2013-11-08 09:59:56.000000000 -0600
***************
*** 43,49 ****
  #if defined(LUA_USE_LINUX)
  #define LUA_USE_POSIX
  #define LUA_USE_DLOPEN                /* needs an extra library: -ldl */
! #define LUA_USE_READLINE      /* needs some extra libraries */
  #define LUA_USE_STRTODHEX     /* assume 'strtod' handles hex formats */
  #define LUA_USE_AFORMAT               /* assume 'printf' handles 'aA' specifiers */
  #define LUA_USE_LONGLONG      /* assume support for long long */
--- 43,49 ----
  #if defined(LUA_USE_LINUX)
  #define LUA_USE_POSIX
  #define LUA_USE_DLOPEN                /* needs an extra library: -ldl */
! // #define LUA_USE_READLINE   /* needs some extra libraries */
  #define LUA_USE_STRTODHEX     /* assume 'strtod' handles hex formats */
  #define LUA_USE_AFORMAT               /* assume 'printf' handles 'aA' specifiers */
  #define LUA_USE_LONGLONG      /* assume support for long long */
diff -r -c lua-5.2.2/src/Makefile ellcc/lua-5.2.2/src/Makefile
*** lua-5.2.2/src/Makefile      2012-12-27 04:51:43.000000000 -0600
--- ellcc/lua-5.2.2/src/Makefile        2013-11-08 21:34:36.494043682 -0600
***************
*** 6,14 ****
  # Your platform. See PLATS for possible values.
  PLAT= none
  
! CC= gcc
  CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
  LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
  LIBS= -lm $(SYSLIBS) $(MYLIBS)
  
  AR= ar rcu
--- 6,16 ----
  # Your platform. See PLATS for possible values.
  PLAT= none
  
! CC= /home/rich/ellcc/bin/ecc
  CFLAGS= -O2 -Wall -DLUA_COMPAT_ALL $(SYSCFLAGS) $(MYCFLAGS)
+ CFLAGS+= -target arm-ellcc-linux-eabi -mcpu=armv6z -mfpu=vfp -mfloat-abi=softfp
  LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
+ LDFLAGS+= -target arm-ellcc-linux-eabi
  LIBS= -lm $(SYSLIBS) $(MYLIBS)
  
  AR= ar rcu
***************
*** 103,109 ****
  generic: $(ALL)
  
  linux:
!       $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline"
  
  macosx:
        $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline"
--- 105,111 ----
  generic: $(ALL)
  
  linux:
!       $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl"
  
  macosx:
        $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline"
[~] dev% 

Then I just typed:

[~/ellcc] dev% cd lua-5.2.2/
[~/ellcc/lua-5.2.2] dev% make linux

I now have my ARM lua exectiable:

[~/ellcc/lua-5.2.2] dev% file src/lua
src/lua: ELF 32-bit LSB executable, ARM, version 1, statically linked, BuildID[sha1]=0x635737dc31e9d493f06b8f9fa5d2e7e3c1fe93ee, not stripped
[~/ellcc/lua-5.2.2] dev% 

Which I can run with QEMU (I use an x86_64 Linux box and don’t have ARM hardware handy):

[~/ellcc/lua-5.2.2] dev% ~/ellcc/bin/qemu-arm src/lua
Lua 5.2.2  Copyright (C) 1994-2013 Lua.org, PUC-Rio
> 

I then went to Lua’s live demo page and cut and pasted an example program:

> -- hello.lua
-- the first program in every language

io.write("Hello world, from ",_VERSION,"!\n")> > > 
Hello world, from Lua 5.2!
> 

Nice!