Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

To keep things manageable, let's use a concrete example Suppose the ELF program that we wish to add to the release code is the since source file hello.c:

Code Block

  #include <stdio.h>
Code Block
  int main(int argc, char **argv)
  {
    printf("Hello from Add-On Program!\n");
    return 0;
  }


Let's say that we have a a directory called addon and contains the hello.c source file, a Makefile that will create the the ELF program, and a Bash script called mkdefines.sh that will create the a linker script.

...

This is the Makefile that I used to create ELF program:

Code Block
  include nuttx-export-7.25/build/Make.defs
Code Block
  # Long calls are need to call from RAM into FLASH
Code Block
  ARCHCFLAGS += -mlong-calls
  ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
  ARCHOPTIMIZATION = -Os -fno-strict-aliasing -fno-strength-reduce -fomit-frame-pointer
  ARCHINCLUDES = -I. -isystem  nuttx-export-7.25/include
Code Block
  CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHINCLUDES) -pipe
Code Block
  CROSSDEV = arm-none-eabi-
  CC = $(CROSSDEV)gcc
  LD = $(CROSSDEV)ld
  STRIP = $(CROSSDEV)strip --strip-unneeded
Code Block
  # Setup up linker command line options
Code Block
  LDRELFLAGS = -r
Code Block
  LDELFFLAGS = -r -e main
  LDELFFLAGS += -T defines.ld -T gnu-elf.ld
Code Block

  
# This might change in a different environment
Code Block
  OBJEXT ?= .o
Code Block
  # This is the generated ELF program
Code Block
  BIN = hello
  REL = hello.r
Code Block
  # These are the sources files that we use
Code Block
  SRCS = hello.c
  OBJS = $(SRCS:.c=$(OBJEXT))
Code Block
  # Build targets
Code Block
  all: $(BIN)
  .PHONY: clean
Code Block
  $(OBJS): %$(OBJEXT): %.c
    $(CC) -c $(CFLAGS) -o $@ $<
Code Block
  System.map: nuttx-export-7.25/System.map
    cat nuttx-export-7.25/System.map | sed -e "s/\r//g" >System.map
Code Block
  $(REL): $(OBJS)
    $(LD) $(LDRELFLAGS) -o $@ $<
Code Block
  defines.ld: System.map $(REL)
    ./mkdefines.sh System.map "$(REL)" >defines.ld
Code Block
  $(BIN): defines.ld $(REL)
    $(LD) $(LDELFFLAGS) -o $@ $(REL)
    $(STRIP) $(REL)
Code Block
  clean:
    rm -f $(BIN)
    rm -f $(REL)
    rm -f defines.ld
    rm -f System.map
    rm -f *.o


The Linker Script

...

The main linker script that I am using in this example, gnu-elf.ld, contains the following:

Code Block

  SECTIONS
  {
    .text 0x00000000 :
      {
        _stext = . ;
      *(.text)

...


      *(.text.*)

...


      *(.gnu.warning)

...


      *(.stub)

...


      *(.glue_7)

...


      *(.glue_7t)

...


      *(.jcr)

...

Code Block
        _etext = . ;
      }
Code Block
    .rodata :
      {
        _srodata = . ;
      *(.rodata)

...


      *(.rodata1)

...


      *(.rodata.*)

...


      *(.gnu.linkonce.r*)

...

Code Block
        _erodata = . ;
      }
Code Block
    .data :
      {
        _sdata = . ;

...

      *(.data)
      *(.data1)

...


      *(.data.*)

...


      *(.gnu.linkonce.d*)

...

Code Block
        _edata = . ;
      }
Code Block
    .bss :
      {
        _sbss = . ;
      *(.bss)

...


      *(.bss

...

.*)
      *(.sbss)

...


      *(.sbss.*)

...


      *(.gnu.linkonce.b*)

...


      *(COMMON)

...

Code Block
        _ebss = . ;
      }
Code Block
      /* Stabs debugging sections.    */
Code Block
      .stab 0 : { *(.stab) }
      .stabstr 0 : { *(.stabstr) }
      .stab.excl 0 : { *(.stab.excl) }
      .stab.exclstr 0 : { *(.stab.exclstr) }
      .stab.index 0 : { *(.stab.index) }
      .stab.indexstr 0 : { *(.stab.indexstr) }
      .comment 0 : { *(.comment) }
      .debug_abbrev 0 : { *(.debug_abbrev) }
      .debug_info 0 : { *(.debug_info) }
      .debug_line 0 : { *(.debug_line) }
      .debug_pubnames 0 : { *(.debug_pubnames) }
      .debug_aranges 0 : { *(.debug_aranges) }
    }


Creating the defined.ld Linker Script

...

Here is the version of mkdefines.sh that I used in this demo:

Code Block
  #!/bin/bash
Code Block
  usage="Usage: $0 <system-map> <relprog>"
Code Block
  # Check for the required path to the System.map file
Code Block
  sysmap=$1
  if [ -z "$sysmap" ]; then
    echo "ERROR: Missing <system-map>"
    echo ""
    echo $usage
    exit 1
  fi
Code Block
  # Check for the required partially linked file
Code Block
  relprog=$2
  if [ -z "$relprog" ]; then
    echo "ERROR: Missing <program-list>"
    echo ""
    echo $usage
    exit 1
  fi
Code Block
  # Verify the System.map and the partially linked file
Code Block
  if [ ! -r "$sysmap" ]; then
    echo "ERROR:  $sysmap does not exist"
    echo ""
    echo $usage
    exit 1
  fi
Code Block
  if [ ! -r "$relprog" ]; then
    echo "ERROR:  $relprog does not exist"
    echo ""
    echo $usage
    exit 1
  fi
Code Block
  # Extract all of the undefined symbols from the partially linked file and create a
  # list of sorted, unique undefined variable names.
Code Block
  varlist=`nm $relprog | fgrep ' U ' | sed -e "s/^[ ]*//g" | cut -d' ' -f2 | sort - | uniq`
Code Block
  # Now output the linker script that provides a value for all of the undefined symbols
Code Block
  for var in $varlist; do
    map=`grep " ${var}$" ${sysmap}`
    if [ -z "$map" ]; then
      echo "ERROR:  Variable $var not found in $sysmap"
      echo ""
      echo $usage
      exit 1
    fi
Code Block
    varaddr=`echo ${map} | cut -d' ' -f1`
    echo "${var} = 0x${varaddr} | 0x00000001;"
  done


This script basically just uses the nm utility to find all of the undefined symbols in the ELF object. Then it searches for the address of each undefined symbol in the System.map that was created when the released firmware was created. Finally, it uses the symbol name and the symbol address to create each symbol table entry.

...