190 likes | 334 Views
NET+OS 6.0/GNU The GNU Tools. GNU Cross Development Tool Basics. The GNU Cross Development Tools are flexible The flexibility extends beyond the target domain, i.e. they can be run on virtually any UNIX-, Linux- based host platform
E N D
GNU Cross Development Tool Basics • The GNU Cross Development Tools are flexible • The flexibility extends beyond the target domain, i.e. they can be run on virtually any UNIX-, Linux- based host platform • There are a number of components to a complete tool chain: • Assembler and object manipulation tools (binutils) • Cross Compiler (gcc) • C/C++ Run time Libraries (newlib, libstdc++) • Debuggers (gdb, insight) • You also need a deployment method to transfer the code to the target system (Raven, Jeeni, Majic, Multi ICE, …)
Cross Tool Identification • To allow several sets of cross development tools to reside on the same host platform, each tool chain is given a name that identifies the target system. The tool name is appended to the toolchain name. • Usually three prefixes are used to identify the tool chain: • machine: identifies the target processor (MIPS, ARM, …) • system: identifies the target system (TBD) • output format: identifies the output (elf, coff, …) • For our System the compiler is called with: • arm-elf-gcc resp. arm-unknown-elf-gcc • This identifies the machine as ARM, the system as unknown (generic) and the output format as elf.
Hidden Tool Components • There are some hidden tool components, such as: • Header files or Includes • Libraries • Linker Scripts • Startup Files • So when using a paricular tool chain it is important that the correct links are set up, not only to the executables but also to the additional (hidden) components above, that are needed to produce a deployable binary • Most of the settings are done when configuring and building a tool chain for a particular target platform.
How to build an Executable? • You would need a source file, lets take the good old K&R Hello world example: • Build: • arm-elf-gcc –g -c test.c –o image.elf • Examine endianess and startaddress arm-elf-strip –O srec image.elf –o image.s3 arm-elf-objdump –d image.elf > image.S • Another Build:arm-elf-gcc –mbig-endian –g -c test.c –o image.elf • Examine endianess and startaddress arm-elf-strip –O srec image.elf –o image.s3 arm-elf-objdump –d image.elf > image.S
Examine Default Compile Specs • Where do the default settings (search pathes, start- address, etc.) come from? • The compiler can be asked to print out the information • when called with: arm-elf-gcc –dumpspecs • The linker control information is coming from/usr/arm-elf/lib/ldscripts • Exercise: Can the above generated code be run on the target?
How to run the Code? • We need a target (developent board) • We need an ICE (Raven, Jeeni, Majic, …) • The target needs some basic initialization first, usually done with the help of an initialization script • The debugger is invoked witharm-elf-gdbtk image.elf –x=jeeni.gdbinit Debugger Console window
What is the Initialization script for? target rdi e=jeeni set endian big set {long}0xffb00000 = 0x4004a000 set {long}0xffc00000 = 0x0dc00000 set {long}0xffc00024 = 0xf3000070 set {long}0xffc00020 = 0x0000022d set {long}0xffc00028 = 0x00000001 set {long}0xffc00014 = 0xf3f00570 set {long}0xffc00018 = 0x00000005 set {long}0xffc00010 = 0x02000003 x/x 0xffc00000 x/x 0xffc00010 x/x 0xffc00014 x/x 0xffc00020 x/x 0xffc00024 load ./image.elf b main run ICE selection Mem.-controller and CSinitalization Read back some values Load executable, set BP in main() and run
Netsilicon specifics The GNU toolchain (binutils, gcc, newlib, gdb) is generic for ARM (prefix arm-unknown-elf-). The startup file (crt0.S), the libraries (libc, libg), and the linker scripts need modifications in order to support the NET+OS system. In order not to “pollute“ the generic toolchain the startup file, the libraries, and the linker scripts are kept in a seperate directories (sources are available) and the linker is told to use the modified files.
The Hello World example again TOOLDIR = /usr NETOS_INSTALLPATH = /cygdrive/c/NETOS60_GNU CC = $(TOOLDIR)/bin/arm-elf-gcc CFLAGS = -g -mbig-endian LDFLAGS = -mbig-endian -Wl DEFINES = INCDIR = . SRCDIR = -I. NETOS_LIBPATH = $(TOOLDIR)/arm-elf/lib/be NETOS_LIBS = -L $(NETOS_LIBPATH) -lg -lc NETOS_STARTUP = $(NETOS_LIBPATH)/crt0.o \ /lib/gcc-lib/arm-elf/3.2/be/crtbegin.o \ /lib/gcc-lib/arm-elf/3.2/be/crti.o VPATH = $(subst -I$,$,$(SRCDIR)) OBJ = test.o all: image.elf image.elf: $(OBJ) $(CC) $(OBJ) $(LDFLAGS) -nostartfiles $(NETOS_STARTUP) -Tarmelf.x $(NETOS_LIBS) -o $@ %.o: %.c Makefile $(CC) $(DEFINES) $(INCDIR) $(SRCDIR) $(CFLAGS) -c $< .PHONY: clean clean: rm -f image.elf $(OBJ)
The modified Makefile TOOLDIR = /usr NETOS_INSTALLPATH = /cygdrive/c/NETOS60_GNU CC = $(TOOLDIR)/bin/arm-elf-gcc CFLAGS = -g -mbig-endian LDFLAGS = -mbig-endian -Wl DEFINES = -D__GNU__ -DNETOS_GNU_TOOLS -DNET_OS -DNET_WORKS INCDIR = -I$(NETOS_INSTALLPATH)/h/threadx SRCDIR = -I. NETOS_LIBPATH = $(NETOS_INSTALLPATH)/lib/32b NETOS_LIBS = -L $(NETOS_LIBPATH) -ltx -lg -lc NETOS_STARTUP = $(NETOS_LIBPATH)/gnu/crt0.o VPATH = $(subst -I$,$,$(SRCDIR)) ... image.elf: $(OBJ) $(CC) $(OBJ) $(LDFLAGS) -nostartfiles $(NETOS_STARTUP) \ -Tdebug.ld $(NETOS_LIBS) -o $@ ...
The NET+OS Makefile • NET+OS actually uses a couple of makefiles • makefile: This is the main makefile. Only this needs to be modified in case files are added or removed from the project. • makefile.app.inc: This is included in makefile. It does not need any modifications. • makefile.appcc.common: • makefile.appbuild.original: Those two files are included in makefile.app.inc. Like makefile.app.inc, these files stay as they are. • The main makefile resides in the projects 32b directory • The remaining three sub-makefiles reside in /netos/src/linkerScripts
The NET+OS Linker Control Script • All application builds are based on a linker control script wich defines the memory map. The name of the linker control script is image.ld • This is a generated file (part of the BSP build) and it is located in /netos/src/linkerScripts • It is generated using the C preprocessor (cpp) from the files image.ldr (in /netos/src/bsp/arm<X>init, <X>=7,9), and customize.ldr (in /netos/src/bsp/platforms/<platform>) • Only customize.ldr needs to be modified if the desired memory map does not fit the default • After modifying customice.ldr a BSP rebuild will be required to generate a new image.ld
A closer look to image.ld • image.ld is used by the linker when generating the application image • It defines where particular code and data sections are placed in memory • It also defines the ordering of the sections and generates symbols which can be accessed by the code • Changes should not be applied directly to this file, the method via the customize.ldr file is the preferred one • Be careful with different versions of toolchain components, other than those delivered with the NET+OS package. The likelyhood to run into issues is fairly high.
A closer look to image.ld (cont.) MEMORY { LOW_RAM : ORIGIN = 1K, LENGTH = 16K - 1K CODE_RAM : ORIGIN = 16K, LENGTH = 2M HIGH_RAM : ORIGIN = (16K + 2M), LENGTH = (16M - (16K + 2M)) } ENTRY(__vectors) SECTIONS { _NAAppOffsetInFlash = 64K; _NABootloaderSizeInFlash = 64K; _NAAppMaxSizeInFlash = (2M - (64K + 64K)); _NABspApplicationImageSize = 2M; _NABspApplicationFlashAddress = 0x50000000 + 64K; _NABspFlashSize = 2M; _NABspFlashStart = 0x50000000; _NABspRamSize = 16M; _NABspFileSystemSizeAddress = 256K; .init : { *(.init) } > CODE_RAM .text : { ... These settings are coming from customize.ldr Linker defined symbols Place the .init section in RAM starting ataddress 0x4000 (16k), followed by .text
A closer look to image.ld (cont.) ... .text : { btext = .; *(.text) ... _endtext = .; } > CODE_RAM restartBuf : AT(_endtext) { gnu_ncc_initdata = .; /* Start of buffer used to store BSP specific data */ . = . + 0x10; gnu_initdata = .; /* Start of buffer used to store application data */ . = . + 1K; /* typically used to hold switch and button settings read at power up*/ } > LOW_RAM .data :AT (_endtext + SIZEOF(restartBuf)) { _etext = _endtext + SIZEOF(restartBuf); __data_start__ = .; *(.data) ... __data_end__ = .; } > HIGH_RAM ... Following the code section (.text) we go onwith the restart buffer (to hold BSP and application specific data) and the .data sectionholding the initializers The symbol _etext will be usedby the startup code (crt0.S) to locate the initializers for initializedvariables
A closer look to image.ld (cont.) • Watch the command to place the .data section: .data :AT (_endtext + SIZEOF(restartBuf)) • { • _etext = _endtext + SIZEOF(restartBuf); • __data_start__ = .; • *(.data) • ... • __data_end__ = .; • } > HIGH_RAM • .data :AT (<expression>) actually places the .data section at the given address, the so called Load Memory Address. It basically becomes part of the image. However, the construct “> HIGH_RAM“ at the end defines a so called VMA (Virtual Memory Address). That means that variables actually accessed at addresses >= HIGH_RAM. • It‘s part of the startup code to copy the initializers from the LMA to the VMA.
The Startup File (crt0.S) start: _start: _mainCRTStartup: ... ldr a1, .LC4 /* dest: __data_start__ */ ldr a2, .LC5 /* src: _etext */ ldr a3, .LC6 /* __data_end__ */ sub a3, a3, a1 /* calculate length */ bl memcpy ... ldr a1, .LC1 /* dest: __bss_start__ */ ldr a3, .LC2 /* __bss_end__ */ sub a3, a3, a1 /* calculate length */ bl memset ... done: bl __gnu_lock_init /* make sbrk() thread save */ mov r0, #0 mov r1, #0 bl main /* call main() w/o arguments */ bl exit /* call exit when returning */ Copy initializers Clear zero vars
Changes to the C Runtime Library • Remember: The toolchain components including the C Runtime library were built for a generic ARM system. In order to support file I/O and dynamic, thread save memory allocation, the generic UNIX style level 2 system functions like open(), close(), read(), write(), sbrk(), …, need to be modified. • Modification can be done in two ways: • Modify the newlib source tree and add another system (e.g. netos) subdirectory to hold the modified level 2 sys. Functions. Followingly configure and build newlib for an arm-netos-elf target. • Take the generic functions from the generic newlib souce tree, modify and compile them seperately and patch the C library • Netsilicon has taken the latter approach. All the sources and makefiles which will be necessary to modify the generic C library are part of the package and are to be found under /netos/gnusrc