# automatically compute structure offsets for gcc targets in ELF format # (C) 2018 Kai-Uwe Bloem. This work is placed in the public domain. # # usage: mkoffsets CC=${CC:-gcc} # endianess of target (automagically determined below) ENDIAN= # check which object format to dissect READELF= OBJDUMP= check_obj () { # prepare an object file; as side effect dtermine the endianess CROSS=$(echo $CC | sed 's/gcc.*//') echo '#include ' >/tmp/getoffs.c echo "const int32_t val = 1;" >>/tmp/getoffs.c $CC $CFLAGS -I .. -c /tmp/getoffs.c -o /tmp/getoffs.o || exit 1 # check for readelf; readelf is the only toolchain tool not using bfd, # hence it works with ELF files for every target if file /tmp/getoffs.o | grep -q ELF; then if command -v readelf >/dev/null; then READELF=readelf elif command -v ${CROSS}readelf >/dev/null; then READELF=${CROSS}readelf fi fi if [ -n "$READELF" ]; then # find the the .rodata section (in case -fdata-sections is used) rosect=$($READELF -S /tmp/getoffs.o | grep '\.rodata\|\.sdata' | sed 's/^[^.]*././;s/ .*//') # read .rodata section as hex string (should be only 4 bytes) ro=$($READELF -x $rosect /tmp/getoffs.o | grep '0x' | cut -c14-48 | tr -d ' \n' | cut -c1-8) # if no output could be read readelf isn't working if [ -z "$ro" ]; then READELF= fi fi # if there is no working readelf try using objdump if [ -z "$READELF" ]; then # objdump is using bfd; try using the toolchain objdump first # since this is likely working with the toolchain objects if command -v ${CROSS}objdump >/dev/null; then OBJDUMP=${CROSS}objdump elif command -v objdump >/dev/null; then OBJDUMP=objdump fi # find the start line of the .rodata section; read the next line ro=$($OBJDUMP -s /tmp/getoffs.o | awk '\ /Contents of section.*(__const|.r[o]?data|.sdata)/ {o=1; next} \ {if(o) { gsub(/ .*/,""); $1=""; gsub(/ /,""); print; exit}}') # no working tool for extracting the ro data; stop here if [ -z "$ro" ]; then echo "/* mkoffset.sh: no readelf or not ELF, offset table not created */" >$fn echo "WARNING: no readelf or not ELF, offset table not created" exit fi fi # extract decimal value from ro rodata=$(printf "%d" 0x$ro) ENDIAN=$(if [ "$rodata" -eq 1 ]; then echo be; else echo le; fi) } # compile with target C compiler and extract value from .rodata section compile_rodata () { $CC $CFLAGS -I .. -c /tmp/getoffs.c -o /tmp/getoffs.o || exit 1 if [ -n "$READELF" ]; then # find the .rodata section (in case -fdata-sections is used) rosect=$(readelf -S /tmp/getoffs.o | grep '\.rodata\|\.sdata' | sed 's/^[^.]*././;s/ .*//') # read .rodata section as hex string (should be only 4 bytes) ro=$(readelf -x $rosect /tmp/getoffs.o | grep '0x' | cut -c14-48 | tr -d ' \n' | cut -c1-8) elif [ -n "$OBJDUMP" ]; then # find the start line of the .rodata section; read the next line ro=$($OBJDUMP -s /tmp/getoffs.o | awk '\ /Contents of section.*(__const|.r[o]?data|.sdata)/ {o=1; next} \ {if(o) { gsub(/ .*/,""); $1=""; gsub(/ /,""); print; exit}}') fi if [ "$ENDIAN" = "le" ]; then # swap needed for le target hex="" for b in $(echo $ro | sed 's/\([0-9a-f]\{2\}\)/\1 /g'); do hex=$b$hex; done else hex=$ro fi # extract decimal value from hex string rodata=$(printf "%d" 0x$hex) } # determine member offset and create #define get_define () # prefix struct member member... { prefix=$1; shift struct=$1; shift field=$(echo $* | sed 's/ /./g') name=$(echo $* | sed 's/ /_/g') echo '#include ' > /tmp/getoffs.c echo '#include ' >> /tmp/getoffs.c echo "static struct $struct p;" >> /tmp/getoffs.c echo "const int32_t val = (char *)&p.$field - (char*)&p;" >>/tmp/getoffs.c compile_rodata line=$(printf "#define %-20s 0x%04x" $prefix$name $rodata) } fn="${1:-.}/pico_int_offs.h" if echo $CFLAGS | grep -qe -flto; then CFLAGS="$CFLAGS -fno-lto"; fi check_obj # output header echo "/* autogenerated by mkoffset.sh, do not edit */" >$fn echo "/* target endianess: $ENDIAN, compiled with: $CC $CFLAGS */" >>$fn # output offsets get_define OFS_Pico_ Pico video reg ; echo "$line" >>$fn get_define OFS_Pico_ Pico m rotate ; echo "$line" >>$fn get_define OFS_Pico_ Pico m z80Run ; echo "$line" >>$fn get_define OFS_Pico_ Pico m dirtyPal ; echo "$line" >>$fn get_define OFS_Pico_ Pico m hardware ; echo "$line" >>$fn get_define OFS_Pico_ Pico m z80_reset ; echo "$line" >>$fn get_define OFS_Pico_ Pico m sram_reg ; echo "$line" >>$fn get_define OFS_Pico_ Pico sv ; echo "$line" >>$fn get_define OFS_Pico_ Pico sv data ; echo "$line" >>$fn get_define OFS_Pico_ Pico sv start ; echo "$line" >>$fn get_define OFS_Pico_ Pico sv end ; echo "$line" >>$fn get_define OFS_Pico_ Pico sv flags ; echo "$line" >>$fn get_define OFS_Pico_ Pico rom ; echo "$line" >>$fn get_define OFS_Pico_ Pico romsize ; echo "$line" >>$fn get_define OFS_Pico_ Pico est ; echo "$line" >>$fn get_define OFS_PicoIn_ PicoInterface opt ; echo "$line" >>$fn get_define OFS_PicoIn_ PicoInterface filter ; echo "$line" >>$fn get_define OFS_PicoIn_ PicoInterface AHW ; echo "$line" >>$fn get_define OFS_EST_ PicoEState DrawScanline ; echo "$line" >>$fn get_define OFS_EST_ PicoEState rendstatus ; echo "$line" >>$fn get_define OFS_EST_ PicoEState DrawLineDest ; echo "$line" >>$fn get_define OFS_EST_ PicoEState DrawLineDestIncr ; echo "$line" >>$fn get_define OFS_EST_ PicoEState HighCol ; echo "$line" >>$fn get_define OFS_EST_ PicoEState HighPreSpr ; echo "$line" >>$fn get_define OFS_EST_ PicoEState Pico ; echo "$line" >>$fn get_define OFS_EST_ PicoEState PicoMem_vram ; echo "$line" >>$fn get_define OFS_EST_ PicoEState PicoMem_cram ; echo "$line" >>$fn get_define OFS_EST_ PicoEState PicoOpt ; echo "$line" >>$fn get_define OFS_EST_ PicoEState Draw2FB ; echo "$line" >>$fn get_define OFS_EST_ PicoEState Draw2Width ; echo "$line" >>$fn get_define OFS_EST_ PicoEState Draw2Start ; echo "$line" >>$fn get_define OFS_EST_ PicoEState HighPal ; echo "$line" >>$fn get_define OFS_PMEM_ PicoMem vram ; echo "$line" >>$fn get_define OFS_PMEM_ PicoMem vsram ; echo "$line" >>$fn get_define OFS_PMEM32x_ Pico32xMem pal_native ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ is_slave ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_bios ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_da ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_sdram ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_rom ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_dram ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_drcblk_da ; echo "$line" >>$fn get_define OFS_SH2_ SH2_ p_drcblk_ram ; echo "$line" >>$fn