XCore cross-toolchain is combined from two major parts: binutils and gcc. To build them you have to provide the proper sysroot directory, modify some source code and configure sources. The whole process is tricky.
First, you have to choose the location to install the cross-toolchain. The usual choice is /opt/TARGET. For example, /opt/BeagleBoneBlack. You have to copy the sysroot directory there (headers only on this stage).
The you need a directory for the source code, like ~/Downloads. When you have downloaded the source code of the binutils and gcc, unpack it here. You got two directories like binutils-2.25.1 and gcc-5.2.0-cross. Then create a directory Build and inside two directories with the same names. They serve as build locations.
Building binutils is simple enough. Create the file MakeCfg in the build directory. It should look like this one:
# MakeCfg CONFIGURE = ../../binutils-2.25.1/configure OPT = --program-prefix=arm- \ --prefix=/opt/BeagleBoneBlack \ --with-sysroot=/opt/BeagleBoneBlack/sysroot \ TARGET = arm-eabielf all: $(CONFIGURE) $(OPT) --target=$(TARGET)
Next you have to modify the source code. The reason is we need a proper linker script to be embedded in the linker during the build process. When you invoke a linker to build the image it uses some file called the linker script to do the job. You may specify such file from the command line, but the more convenient way is to embed it into the linker. The actual changes depend on your target, target memory map and low-level details of the XCore implementation.
For example, for the BeagleBoneBlack target we uses the following script features. The symbol __std_image_base is the text start address, this symbol is defined in the startup code. The symbol __std_start is the entry point. The images is started with the section .absstart. Then the section .context_data is used to store some task specific variables. The content of this section is preserved during the task switch process. So the linker script has the part
.context_data ALIGN(4) : { . = ALIGN(4) ; __std_context_data = . ; *(.context_data) . = ALIGN(4) ; __std_context_data_lim = . ; }
This part combines all .context_data into the one and defines two symbols __std_context_data and __std_context_data_lim to designate the section location in the memory.
Finally, the linker defines two symbols __std_mem and __std_mem_lim for the large unassigned memory after the loaded image in the RAM.
.mem ALIGN(16) : { . = ALIGN(16) ; __std_mem = . ; . = . + __std_mem_size ; . = ALIGN(16) ; __std_mem_lim = . ; }
The size of this block is defined by the symbol __std_mem_size from the startup code.
Once you finished with the source code modification issue the following command make -f MakeCfg in the build directory. It starts the configuration process. After that use the command make to perform the actual build and make install to install the tools.
Building gcc is essentially the same. The only difference is the source code modification is more tricky.
The first step is the configuration. Create the file MakeCfg in the build directory. It should look like this one:
# MakeCfg CONFIGURE = ../../gcc-5.2.0-cross/configure OPT = --program-prefix=arm- \ --prefix=/opt/BeagleBoneBlack \ --with-local-prefix=/opt/BeagleBoneBlack/arm-eabielf \ --with-sysroot=/opt/BeagleBoneBlack/sysroot \ --with-arch=armv7-a \ --with-fpu=vfpv3 \ --with-float-abi=hard \ --enable-languages=c,c++ \ --enable-c99 \ --enable-long-long \ --disable-shared \ --disable-libssp \ TARGET = arm-eabielf all: $(CONFIGURE) $(OPT) --target=$(TARGET)
Then patch source files. For the target BeagleBoneBlack the following modifications are required. We have to correct four source files and configuration script from the C++ support library.
libstdc++-v3/config/io/basic_file_stdio.cc libstdc++-v3/libsupc++/eh_alloc.cc libstdc++-v3/libsupc++/eh_globals.cc libstdc++-v3/libsupc++/pure.cc libstdc++-v3/configure
The file basic_file_stdio.cc contains the basic io class implementation. It must be replaced to use standard stdio functions.
eh_alloc.cc contains the code for the exception handling. It uses standard memory allocation functions malloc() and free() to allocate a space for exception objects. The code must be changed to use malloc_int() and free_int() instead. And the "emergency buffer" must be removed.
eh_globals.cc contains definitions of the global variables for the exception handling subsystem. The problem is these variables must be per-task. But we configure compiler for single-thread support only. So we have to handle this matter ourself. In BeagleBoneBlack global variables, placed in the section .context_data, instead of .data, preserved on a task switch. So these variables are per-task variables. To use it we declare some variables in the eh_globals.cc to be placed in the section .context_data.
// Single-threaded fallback buffer. static __cxa_eh_globals eh_globals __attribute__((section(".context_data"))) = {} ;
pure.cc print the message in case of the pure virtual function call. We have to change this file to use stdio print functions.
configure script have two problems. It emits error for unknown OS. So we have to disable it.
# as_fn_error "No support for this host/target combination." "$LINENO" 5 // line 77171
The second problem is to disable attempts to link target applications. It can be done by adding the following line at the proper place.
gcc_no_link=no // line 10555
Once you finished with the source code modification issue the following command make -f MakeCfg in the build directory. It starts the configuration process. After that use the command make to perform the actual build and make install to install the tools.
You can reuse the approach from the BeagleBoneBlack for your own XCore targets. If the target uses ARM-v7 or later you can also reuse major parts of the startup code.