These instructions are designed around getting VxWorks development going on a Linux host for an x86 target. Please don't become confused by the fact that the target is x86 and think you're not running a VxWorks kernel on it. As a matter of fact, I think these instructions are applicable to non-x86 Linux hosts. I'll be working on that soon.
Many thanks go out to the originator of this page, Kevin Bradley, who is a credit to the CMU Technical Alumni.
WindRiver doesn't support Linux like it supports Solaris, HP-UX, or Windows -- there are no supplied tools. However, Linux has certain attractions, as it's somewhat more stable than Windows, is cheaper, and so forth.
In addition, the use of an x86 BSP is desirable, as a plain old PC (and even an OLD PC, a 386 or 486 that no-one wants any more) can be used adequately. Really all that's needed is a network card and a motherboard and some RAM; the rest (graphics, disk, etc.) isn't required.
If you have an x86 BSP, and Tornado 1.0 / 1.0.1, the provided tools don't work too well for C++ code, which the 2.6-era GCC that comes with 1.0 doesn't like, and 2.7.2 doesn't support well. A newer version of GCC ported as a cross-compiler for VxWorks is needed. People on the mailing list have said repeatedly that it's easy. Well, it is for 68k, i960, and other CPUs, because GCC has built-in options for these. Just identify the target as XXX-vxworks, and it builds happily.
The x86 has no such built-in option (gcc 2.7.2.2 doesn't, anyway), so
some hacking and porting is required.
Note: Dr. Max Fischer Max.Fischer@dlr.de reports that these steps work for gcc-2.8.1 and binutils-2.9.1, so don't lose heart at the age of these files.
What are these?
WindRiver supplies all of these programs in its Tornado distribution with a name modifier to indicate they're cross compilers. Here's the list from my distribution for x86-win32 host, and x86 target:
ar386.exe cppfilt386.exe objcopy386.exe strings386.exe
as386.exe gasp386.exe objdump386.exe strip386.exe
cc386.exe ld386.exe ranlib386.exe
cpp386.exe nm386.exe size386.exe
Under Linux, we'll end up with programs similar to these: the main program name, and some modifier indicating its cross-compiler nature.
We have to compile binutils first, and then gcc, as gcc depends on binutils.
--host: Gives the name of the host system. If it can't be auto-detected, which sometimes happens under Linux (my system of i686-pc-gnu-linux isn't recognized, but you can fake it as i486-linux, which is).
--target: Gives the name of the target system. This will be i386-wrs-vxworks, indicating the processor, system manufacturer, and OS.
--prefix: Where we want to install libraries and other information starting from. If you don't have root access, or don't want things in /usr/local (the default), use this. It's possible to redirect things to your $HOME (/home for this discussion) directory.
--exec-prefix: Similar in intention; where the binaries go. The end result is ${exec-prefix}/bin; we want $HOME/bin, so $HOME is used for this as well.
The first one is for "libiberty", which is a common library containing useful subroutines, and also contains configuration information. It should have a file called "mt-vxworks5", which contains information about what files libiberty needs. No modification is necessary.
The second one is for "bfd", the object file library. This library is used by the debugger, assembler, linker, and pretty much everything else. The important file is config.bfd, which sets some variables containing the "type" of object file (COFF, AOUT, ELF, others), vector sizes, whether to generate underscores, etc. There are some vxworks entries (a29k-*-vxworks, i960-*-vxworks, m68-*-vxworks) already present, but no ix86-*-vxworks. We need to make one.
In the i[3456]86 section, add the following to make a config.bfd file that recognizes x86-vxworks as a target system. Note: The spaces here are important. If you use cut / paste from your browser into config.bfd, ensure that config.bfd ends up with the proper spacing (the same as before, basically). Dr. Max Fischer (Max.Fischer@dlr.de) reports this is a potential source of confusion.
i[3456]86-*-vxworks) targ_defvec=i386aout_vec targ_underscore=yes ;;This says that we're making aout files (which is in agreement with the documentation about vxWorks and x86 BSPs).
The third one is for "opcodes", which contains the information about opcode names and register usage. No changes are necessary.
The fourth is in "ld", which tells the linker what kind of output files to make. There's no line for x86-*-vxworks in the file configure.tgt, so we have to make one saying we're making i386aout files to make a proper configure.tgt:
i[3456]86-*-vxworks) targ_emul=i386aout ;;
After these two small changes are made, we issue the configure command in {}/binutils-2.8/:
==> ./configure --host=i486-linux --target=i386-wrs-vxworks --prefix=/home --exec-prefix=/home
Obviously, substitute for your host, prefix, and exec-prefix.
Wait a bit, as a lot of configuration has to go on. It should eventually terminate with some messages like this:
Created "Makefile" in /home/src/binutils-2.8.0.3
You should see binaries appear in your {}/bin directory looking like this:
/home/bin/i386-wrs-vxworks-addr2line
/home/bin/i386-wrs-vxworks-ar
/home/bin/i386-wrs-vxworks-as
/home/bin/i386-wrs-vxworks-c++filt
/home/bin/i386-wrs-vxworks-gasp
/home/bin/i386-wrs-vxworks-ld
/home/bin/i386-wrs-vxworks-nm
/home/bin/i386-wrs-vxworks-objcopy
/home/bin/i386-wrs-vxworks-objdump
/home/bin/i386-wrs-vxworks-ranlib
/home/bin/i386-wrs-vxworks-size
/home/bin/i386-wrs-vxworks-strings
/home/bin/i386-wrs-vxworks-strip
In addition, you should see a $prefix/i386-wrs-vxworks directory, which contains bin/, lib/ldscripts/, and include/.
bin/ contains symlinks or copies of the binaries, depending.
lib/ldscripts/ contains scripts that ld uses in its linking process. We have:
i386aout.x i386aout.xn i386aout.xu i386coff.xbn i386coff.xr
i386aout.xbn i386aout.xr i386coff.x i386coff.xn i386coff.xu
I'm not sure what they're for entirely; they seem to contain directions about different sections of the object file.
binutils is now complete.
First, we have to look at the "configure" script itself. The --target directive is resolved here, so we need to make an entry for i386-wrs-vxworks.
Based on the other "*-vxworks" entries, We made the following modification to the configure script at the end of the i386 section:
i386-wrs-vxworks*) tmake_file=i386/t-vxworks tm_file=i386/vx386.h use_collect2=yes ;;The "tmake_file" contains some compiler directives, such as what to while building libgcc, and so forth.
Based on "t-vxworks" found in other architectures (m68k, a29k, i960), We construct the following t-vxworks file, which then resides in config/i386/:
# The i386 md has all of these taken care of, according to sef. LIBGCC1 = CROSS_LIBGCC1 = # We don't want to put exit in libgcc.a for VxWorks, because VxWorks # does not have _exit. LIBGCC2_CFLAGS = -O2 $(GCC_CFLAGS) -g1 -Dexit=unused_exit
The configure script also refers to an include file
vx386.h.
This include file contains some information for the compiler about the
type of assembly language to produce (so that as can understand
it) and some startup and library information.
As VxWorks has a shared-library principle (through the dynamic linking), and we're really making function calls to run a program, there are no start files or libraries to link with (obviously, the kernel does, but we specifically include them on the command line rather than telling gcc to look for them by default).
Before, we configured as for a.out (along with the rest of binutils). So we have to tell gcc to produce a.out assembly code. The easiest way to do this is include the "i386-aout" header file, which contains all the proper setup information for gcc.
So we end up with vx386.h:
#include "i386-aout.h" /* VxWorks does all the library stuff itself. */ #undef LIB_SPEC #define LIB_SPEC "" /* VxWorks provides the functionality of crt0.o and friends itself. */ #undef STARTFILE_SPEC #define STARTFILE_SPEC ""Once all these small changes are made, we can issue the configure command:
==> ./configure --host=i486-linux --target=i386-wrs-vxworks --prefix=/home --exec-prefix=/home
After a bit, you should see messages like this:
Using `./config/i386/i386.c' to output insns. Using `./config/i386/i386.md' as machine description file. Using `./config/i386/vx386.h' as target machine macro file. Using `./config/i386/xm-linux.h' as host machine macro file. Merged x-linux. Merged i386/t-vxworks. Merged c++ fragment(s). Created `./Makefile'. Merged x-linux. Merged i386/t-vxworks. Created `cp/Makefile'. Links are now set up to build a cross-compiler for i386-wrs-vxworks from i486-unknown-linux.
You should see binaries like this in ${prefix}/bin:
/home/bin/i386-wrs-vxworks-g++ /home/bin/i386-wrs-vxworks-gccIn addition, you should find a new directory ${prefix}/lib/gcc-lib/i386-wrs-vxworks/2.7.2.2/, which contains some gcc functions and libraries, as well as a "specs" file:
SYSCALLS.c.X cc1obj* cpp* libgcc.a specs* cc1* cc1plus* include/ libobjc.a
You have two choices how to do this. The first is to issue "make" with lots of command-line arguments specifying the compiler, linker, etc. The second is to edit the Makefile and specify these things yourself. The first method is a bit tougher to type, but safer: you don't have to break any Makefiles.
We used the following command line to compile the kernel. The Tornado distribution is mounted as /dosd/Tornado, and the target is pc386, so:
==> cd /dosd/Tornado/target/config/p386 ==> make WIND_BASE=/dosd/Tornado RM=rm clean rm *.o rm vxWorks* rm bootrom* rm depend.pc386This is the "clean out everything" command, so you know it works and isn't trying to read old .o files.
==> make WIND_BASE=/dosd/Tornado RM=rm MKVERSION=mkversion CC=/home/bin/i386-wrs-vxworks-gcc LD=/home/bin/i386-wrs-vxworks-ld CPP=/home/lib/gcc-lib/i386-wrs-vxworks/2.7.2.2/cpp LDOUT_SYMS=echo BINXSYM=/home/bin/i386-wrs-vxworks-xsym ROMSIZEPROG=/home/bin/vxsize /dosd/Tornado/target/h/make/rules.x86-win32:22: depend.pc386: No such file or directory /home/bin/i386-wrs-vxworks-gcc -M -fvolatile -nostdlib -fno-builtin -fno-defer-pop -m486 -Wall -I/h -I. -I/dosd/Tornado/target/config/all -I/dosd/Tornado/target/h -I/dosd/Tornado/target/src/config -I/dosd/Tornado/target/src/drv -ansi -nostdinc -DCPU=I80486 if_eex32.c symTbl.c sysLib.c sysSerial.c vxsys.c ../all/bootConfig.c ../all/bootInit.c ../all/dataSegPad.c ../all/usrConfig.c > depend.pc386 /home/lib/gcc-lib/i386-wrs-vxworks/2.7.2.2/cpp -M -E -I/h -I. -I/dosd/Tornado/target/config/all -I/dosd/Tornado/target/h -I/dosd/Tornado/target/src/config -I/dosd/Tornado/target/src/drv -DCPU=I80486 romInit.s >> depend.pc386 /home/lib/gcc-lib/i386-wrs-vxworks/2.7.2.2/cpp -M -E -I/h -I. -I/dosd/Tornado/target/config/all -I/dosd/Tornado/target/h -I/dosd/Tornado/target/src/config -I/dosd/Tornado/target/src/drv -DCPU=I80486 sysALib.s >> depend.pc386 <after the depend file is built, a lot of compiling, snipped, is performed> mkversion > version.c /home/bin/i386-wrs-vxworks-gcc -c -fvolatile -nostdlib -fno-builtin -fno-defer-pop -m486 -Wall -I/h -I. -I/dosd/Tornado/target/config/all -I/dosd/Tornado/target/h -I/dosd/Tornado/target/src/config -I/dosd/Tornado/target/src/drv -ansi -nostdinc -DCPU=I80486 version.c rm version.c /home/bin/i386-wrs-vxworks-ld -X -N -e _sysInit -Ttext 00108000 \ -o vxWorks dataSegPad.o sysALib.o sysLib.o usrConfig.o version.o /dosd/Tornado/target/lib/libI80486gnuvx.a /dosd/Tornado/user/Pentium_Counters/pentium.out /dosd/tornado/user/Sound_Driver/sound.o /home/bin/i386-wrs-vxworks-xsym < vxWorks > vxWorks.sym /dosd/Tornado/host/x86-win32/bin/vxsize -v 00008000 00108000 vxWorks make: /dosd/Tornado/host/x86-win32/bin/vxsize: Command not foundNow, before you rise up and say, "Wait! What's "mkversion", "vxsize", and "xsym"? Those weren't mentioned! No fair!", read on a bit.
xsym is a small program that produces the symbol table. A kind person posted code for it, and it's available below.
mkversion is a shell script. version.c has two symbols in it: a character string containing the code version (5.3 in my case), and the build date. The script echoes the proper strings out on stdout, and are then compiled in. It could probably be done way more efficiently, but who cares that much?
vxsize is the WindRiver code sizer for ROMs implemented as a shell script wrapper to the binutils size program.
munch is a C++ name demangler / code generator that allows static objects to be initialized on download. It's documented as being important in the compilation process.
One other auxiliary program is the one to produce a boot disk from the bootrom_uncmp binary. In order to make it bootable, the a.out header has to be removed. Well, the Unix program dd can skip this header properly. vxboot is a wrapper to dd.
Thanks to Casey Crellin casey@ccii.co.za
for providing mkversion, mkboot, vxsize, and xsym.c (originally from Lyor
Goldstein).
Thanks to James Wann (james@synerdyne.com)
for the newer munch perl script, described as 'quick-and-dirty' by the
author.
Thanks to Ron Flory (ron.flory@ifrsys.com)
for removing some of the 'dirty' from James's munch script. Jim sez
thanks.
Thanks to Henric Jungheim (junghelh@pe-nelson.com)
for the original munch awk script.
As promised, here are the auxiliary programs:
Our target (another PC) is set to FTP to the Linux system to get its kernel and symbols, and to NFS mount my development directory and /tmp from the Linux machine. Just a warning: NFS under vxWorks is pretty painful, so if you need to stream data, be forewarned. It's ok for loading modules and so forth.
Complaints to Webmaster.
Last modified Feb 01, 1999.