Skip to content
/ tinyc32 Public

tiny C library and toolchain for writing SYSLINUX COM32R executables

Notifications You must be signed in to change notification settings

pts/tinyc32

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tinyc32: A tiny C library and toolchain for writing Syslinux COM32R executables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tinyc32 is a tiny C library and some Python scripts for Unix for creating
tiny Syslinux COM32R executables (.c32 files). tinyc32 calls GCC with the
appropriate flags, which calls GNU ld with the appropriate flags. The COM32R
executables created by tinyc32 are tiny (as little as 178 bytes for
hello-world), because they contain very little overhead.

Dependencies:

* A Unix system, preferably Linux.
* GCC (with the -m32 flag for producing i386 code)
* Works with GCC 4.8.4. (Not tested with Clang.)
* GNU ld from GNU Binutils.
* Python 2.4, 2.5, 2.6 or 2.7.
* (A Syslinux installation or sources are not needed.)

Typical example of how tiny the overhead added by tinyc32: a hello-world
(examples/hello_golden.c32) is 178 bytes, which includes the message of
15 bytes.

Documentation of the COMBOOT (and COM32R) ABI:
http://www.syslinux.org/doc/comboot.txt

Example compilation (run it without the leading $):

  $ ./tinyc32 gcc -o examples/hello.c32 examples/hello_main.c

Example usage in your syslinux.cfg:

  label hello
  kernel hello.c32
  append your  example args

With the default settings, tinyc32 tries to create the smallest possible
executable. This includes passing -Os and -falign-functions (etc.) to GCC.
If you specify an -O... flag other than -Os (recommended for fast code:
-O2), then tinyc32 won't get in your way, e.g. it won't specify any
memory alignment flags to GCC.

tinyc32 has been tested with Syslinux 4.07.

FAQ
~~~
Q1. How does tinyc32 work?
""""""""""""""""""""""""""
A tricky part is the generation of position-independent code, which is
needed because .c32 files can be loaded by Syslinux to any address. `gcc
-fPIC' doesn't work well for extern variables (see
https://stackoverflow.com/q/47846650/97248), so tinyc32 does a regular
compilation and linking, dumping the relocations with `-Wl,-q', and for each
R_386_32 relocation it finds, it adds an `add [dword ebx +
...], ebx' instruction (6 bytes, of which 4 bytes is the address) to the
startup code, which does the relocation at runtime.

Because of these additions, some offsets may be shifted, and this may cause
aligned global variables and functions not aligned anymore. If tinyc32
detects this, then it adds some more padding to fix the alignment, but for
large alignment it does another compilation pass with GCC instead. Use
`-ftinyc32-multipass' to force the 2nd compilation pass.

Q2. Can the executables created by tinyc32 be compressed?
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Yes, with upxbc (http://github.com/pts/upxbc):

  $ ./tinyc32 gcc -o examples/hello.c32 examples/hello_main.c
  $ ./upxbc examples/hello.c32

upxbc uses UPX under the hood to compress the executable. By default it
passes the highest effort flag (`upx --ultra-brute --lzma'). Please note
that for very small executables (smaller than 1 KiB), it's unlikely that
upxbc can make it any smaller.

Q3. How can I try the .c32 I'm developing?
""""""""""""""""""""""""""""""""""""""""""
You can use QEMU on an i386 or amd64 system. On Ubuntu, install it as:

  $ sudo apt-get install qemu-system-x86

Get the mtools tool for copying files into FAT filesystem images:

  $ curl -OL https://github.com/pts/tinyc32/releases/download/helper/mtools
  $ chmod 755 mtools

Get the Syslinux image liigboot_empty.img . It contains a FAT12 filesystem
with Syslinux 4.07 on it. Get it like this

  $ curl -OL https://github.com/pts/tinyc32/releases/download/helper/c32try_empty.img.gz
  $ gzip -cd <c32try_empty.img.gz >c32try.img

Get an example .c32 file to run:

  $ curl -O https://raw.githubusercontent.com/pts/tinyc32/master/examples/hello_golden.c32

Copy your .c32 file you want to try to a.c32 onto the image:

  $ ./mtools -c mcopy -i c32try.img hello_golden.c32 ::a.c32

Run the QEMU emulator in the GUI:

  $ qemu-system-i386 -m 4 -hda c32try.img -machine accel=kvm -net none

It should display something like this in a new black window:

  SeaBIOS (...)
  Booting from Hard Disk...
  MR 0x...
  Hello, World!
  boot: _

The ``Hello, World!'' is the output of the hello_golden.c32, so it has
succeeded. You can run it again by pressing <A> and <Enter>.

If QEMU doesn't start up, drop the `-machine accel=kvm' flag and try again.

Exit from QEMU by closing the black window or presing on Ctrl-<C> in the
terminal window you have started it in.

Q4. I get a linker ``internal error in do_layout''.
"""""""""""""""""""""""""""""""""""""""""""""""""""
If you get:

  /usr/bin/ld: internal error in do_layout, at ../../gold/object.cc:1723

... then probably you are using a broken version of GNU gold (such as GNU
gold 1.11 in Binutils 2.24).

The solution is to make the /usr/bin/ld symlink point to GNU ld rather than
GNU gold. For example, on Ubuntu:

  $ sudo ln -sf ld.bfd /usr/bin/ld

__END__

About

tiny C library and toolchain for writing SYSLINUX COM32R executables

Resources

Stars

Watchers

Forks

Packages

No packages published