Question

I have a rooted Sony reader PRS900, running an OEM linux kernel 2.6.23, and I can run arbitrary bash/sh scripts from the SD memory card drive on it. I want to compile and execute C programs ... but am having dynamic linker problems.

I first tried loading gcc for arm (slackware 14's) on the SD card, but even when using LD_LIBRARY_PATH, the sony will fail to "find" most newer elf .so libraries, although newer programs which use old libraries do in fact run properly. ( I can run slackware-14's "readelf" just fine. but not ar, or gcc...) If I try to upgrade /lib/ld-linux.so.3, I get a "kernel too old" error message.

I then tried an old slackware 10 version of gcc, and although that solves the elf library "finding" problem -- I then get an "illegal instruction" error when running programs.

So -- I need to make a gcc cross compiler on my x86 for the proper ARM processor and then use it to recompile gcc for the sony. But I don't know what legacy version of binutils I must use since it assembles and links to ELF format that either works or breaks on the sony.

The Sony is running an arm6 compatible MX31 EBX5016 processor. and some relevant OEM file names on the sony are:

/lib/ld-2.5.so
/lib/ld-linux.so.3 -> ld-2.5.s 
/lib/libc-2.5.so
/lib/libgcc_s.so.1

I know, from the kernel, that gcc-4.2.0 was used. I would prefer to use the newest version of gcc which will work with whatever legacy binutils package I need to install.

How do I figure out which version of binutils that I need, and what options I have for gcc? Thanks!

Was it helpful?

Solution 2

Sony is using a kernel put out by motavista linux; According to montavista, the compiler for that kernel was made with binutils 2.17. I wasn't able to find any way to figure out which binutils originally developed with which version of GCC from the gnu project itself. Even the repository upload dates vary inconsistently... but I did find which binutils montavista was developed with.

The minimum version of a working cross compiler from stock GCC source code that I was able to make, came from gcc-4.2.0 with binutils 2.19.1 and glibc-2.5 using glibc-ports-2.5 for the arm processor/linux extensions.

The rest of this answer details building that cross compiler from scratch, as a reference for other people wanting to build a linux cross compiler for arm with the gnu c library included; eg: gcc with eabi and glibc for linux: arm-linux-gnueabi- tool.

It's a totally non-trivial problem, and I hope my notes are useful to others.

The sony reader PRS900 uses an EABI compiler to make the kernel, and it is also configured as little endian.

Binutils was switching from arm eabi-V4 to eabi-V5 at the time, and Sony's PRS-900 /lib/ld-* appears to expect the eabi-5 flag to be set or else it gets confused. when linking with binutils, people can accidentally mix eabi 4 and 5 object files which causes most of the problems, because it will default back to eabi-version 4 for the link: so, the way to make sure that eabi 4 is never produced accidentally, is to edit the default header files for the gas (Gnu ASsmebler) so it always defaults to eabi-5 even when building the cross compiler libraries unless explicitly told to do otherwise.

eg: these two files in binutil:

gas/config/te-armeabi.h <--change EABI_VER4 to --> #define EABI_DEFAULT EF_ARM_EABI_VER5

gas/config/te-armlinuxeabi.h <--do same--> #define EABI_DEFAULT EF_ARM_EABI_VER5

It would in fact be easier to use the code-sourcery tools than to build a gcc toolchain, from scratch (I'm going to test them to see if they work on kernel modules, too) -- but as I intend to upgrade to newer tools -- I needed to know how to do this from scratch.

Below: I've included a script which is more important for the notes it contains than for it's usability; eg: It is NOT intended to be run and is not automatic -- but rather, it's to be cut and pasted into a shell and used as a cheat sheet outlining the flags which work and the files which must be manipulated to circumvent bugs. It has comments which are meant to be read, and although imperfect -- a human reading error messages should be able to figure out the rest from the shell's error messages.

I could not get libmudflap, libgomp, or libssp to work in gcc -- no matter how I tried, so they are disabled in the GCC build because all three cause insoluble compiling problems; but other than that, this script shows what is needed to build a "C" cross compiler arm-linux-gnueabi- toolchain which will compile and link Sony PRS-900 binary executables that run without segfaults, or errors.

One note: It does NOT build kernel modules with the correct CRC codes, and it seems that the kernel that sony releases on their website (see previous post) is slightly different than the one on my sony; although the dates are identical and I used the /proc/config.gz from my actual sony. I intend to open a separate thread to solve that problem... but at least one can build user space executables with this cross compiler with no problems.

#!/bin/false
# Do not run this script directly, until you have read and edited source
# files appropriately. It's not automated.  vim is a text editor...

# This script creates a toolchain in a local directory (not root).
# I made it to build a gcc toolchain on a USB memory stick,
# mounted under /media/memory1 on slackware14.
#
# Needed source files:
#
# binutils-2.19.1.tar.bz2
# gcc-core-4.2.0.tar.bz2
# linux-2.6.23_091126.tgz
# glibc-2.5.tar.bz2 
# glibc-ports-2.5.tar.bz2
#
# and from the sony PRS-900, itself, you need file: /proc/config.gz
# To guarantee the kernel is compiled the same.

# First make a local script to set paths for the toolchain once it it built
# --------------

echo -e "\
#!--/bin/bash-- # but must run as . setArmEnvironment.rc \n\
# There are two kinds of binaries for cross compilation, the tool binaries\n\
# and libraries, and the target headers, libraries, etc.\n\
export CROSSROOT="\$PWD/.local"\n\
export TARGETROOT="\$PWD/.target"\n\
export PATH="\$PATH:\$CROSSROOT/bin"\n\
export LD_CONFIG_PATH="\$CROSSROOT/lib:\$LD_CONFIG_PATH"\n\
" >  setArmEnvironment.rc

# ----------

# Next:
# Create the local binary and header directories for the cross compiler toolchain
# .local is the buld machines' local tools for arm development
# This is for the binaries for the machine doing the cross compiling.

mkdir .local
cd .local
ln -s . usr
ln -s . local
mkdir include
mkdir lib
mkdir bin
ln -s include sys-linux
cd ..

# Target is for the host tools, headers, etc.  it is a pure ARM directory.
# Everthing here is potentially installable on the sony itself.
# And is what would appear on the SONY PRS-900 if it had a toolchain.

mkdir .target
cd .target
ln -s . usr
ln -s . local
mkdir include
mkdir lib
mkdir bin
ln -s include sys-linux
cd ..

# Now, we need to set the paths so that as we make build tools, we can
# use them from the shell we are in.

. setArmEnvironment.rc

# FIRST! ----------------------------------------------------------------------

# Problem: GCC supposedly needs some g-libc header files for proper target code
# generation... 
# but they don't really exist until compiled -- so chicken-egg-rooster prob !
# Which to make first...
#
# Solve it by installing headers from uncompiled packages, using a broken gcc/binutils
# then, re-build and re-install proper header files -- re-build proper gcc... etc.

# build a broken binutils package.
tar -xf /tmp/binutils-2.19.1.tar.bz2
mkdir build.binutils.eabi 
cd build.binutils.eabi
../binutils-2.19.1/configure --target=arm-eabi --prefix=$CROSSROOT
# Make with flags to prevent warning creep on newer GCC's compiling older code.
make CFLAGS="-Os -w"
make install
cd ..

# build a broken gcc core.

tar -xf /tmp/gcc-core-4.2.0.tar.bz2
mkdir build.gcc.eabi
cd build.gcc.eabi
../gcc-4.2.0/configure --target=arm-eabi --prefix=$CROSSROOT --enable-multilib --disable-libssp
make CFLAGS="-Os -w"
make install
cd ..

# Install kernel headers using first pass (broken) cross-compiler -------------

tar -xf /tmp/linux-2.6.23_091126.tgz
gzip -d config.gz
cp config linux-2.6.23_091126/.config
cd linux-2.6.23_091126

# The makefile is a little broken for use on slackware 14...
# edit so that:
# CROSS_COMPILE ?= arm-eabi-
# and make the two implicit rules explicit:
# eg: lines 425 and 1476 contain rules that need to be broken into two rules each:
# Here's a patch file to do it automatically -- paste as one quoted unit to shell:
# ******************** START ECHO DIFF COPY/PASTE
echo '192c192
< CROSS_COMPILE ?= /opt/timesys/toolchains/armv6j-linux/bin/armv6j-linux-
---
> CROSS_COMPILE ?= arm-eabi-
422c422
< config %config: scripts_basic outputmakefile FORCE
---
> %config: scripts_basic outputmakefile FORCE
424a425,428
> config: scripts_basic outputmakefile FORCE
>       $(Q)mkdir -p include/linux include/config
>       $(Q)$(MAKE) $(build)=scripts/kconfig $@
> 
1472c1476,1479
< / %/: prepare scripts FORCE
---
> %/: prepare scripts FORCE
>       $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
>       $(build)=$(build-dir)
> /: prepare scripts FORCE
1475c1482
< %.ko: prepare scripts FORCE
---
> %%.ko: prepare scripts FORCE' > Makefile.diff
# ******************** END ECHO DIFF COPY/PASTE
# now apply the patch to the Makefile
patch Makefile Makefile.diff

# You might also need to edit
# vim linux scripts/unidef.c and search all instances of getline, replacing it with _getline to avoid stdio.h overloading conflict.
# This is not always necessary... but if you have the problem... that's the solution.

make ARCH=arm INSTALL_HDR_PATH=$TARGETROOT headers_install
cd ..
# DONE installing kernel header files somewhat sanitized...

 ------------------------ GLibc, headers install 
## Create aliases for binutils so I don't need to fight with glibc...
cd .local/bin
for i in `ls arm-eabi-*`; do ln -s $i arm-linux${i##arm-eabi} ; done
cd ../..


# Now we need to build glibc-2.5 with the arm port (glibc-ports-2.5.tar.gz)
tar -xzf glibc-2.5.tar.gz
cd glibc-2.5
tar -xzf ../glibc-ports-2.5.tar.gz
mv glibc-ports-2.5 ports

# Steal configuration for arm from other processors... probably not needed.
cp sysdeps/wordsize-32/bits/wordsize.h bits # 32bits
cp sysdeps/i386/bits/endian.h bits # little endian
cd ..

# For the first pass, just make enough of libc to install the header files.

mkdir build.glibc.eabi

#bash # Enter a new shell, because path needs to be forced.
# CAUTION: You must not do this as superuser, or with write priveleges to 
# the system directores, as there are bugs in the GLIBC install that
# will try to put them there even though they don't belong there in a cross
# compiler..!
(

cd build.glibc.eabi
export LD_LIBRARY_PATH=""
export PATH=$CROSSROOT/bin:$PATH

echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
echo "libc_cv_arm_tls=yes" >> config.cache # For posix threads, but maybe not.


../glibc-2.5/configure --with-binutils=$CROSSROOT/arm-eabi/bin --build=i686-linux --host=arm-linux --prefix=/usr --enable-kernel=2.6.23 --with-headers=$TARGETROOT/include --enable-add-ons --disable-profile --config-cache --disable-sanity-checks --with-tls --with-__thread

# Caution, this install will attempt to install to both --prefix=/usr AND install_root.
# Because any directories where actual compilation is unfinished will
# not make install_root= correctly, but default back to prefix.
# Therefore,
# Do not allow writes to local system directories, by not installing as root!
# ... AND ...
# You must run make install_headers twice so everything does end up in $TARGETROOT

make -k install-headers install_root=$TARGETROOT
make -k install-headers install_root=$TARGETROOT

# Manually install two files, ... or GCC won't build.  Three if you want it all.
# Glibc has a *REAAAALY* crappy installer script ...
cp bits/stdio_lim.h $TARGETROOT/include/bits
touch $TARGETROOT/include/gnu/stubs.h
cp nptl/sysdeps/pthread/pthread.h $TARGETROOT/include

# Long-double is messed up ... I ran into this. :)
( cd $TARGETROOT/include/bits
      sed '/ifndef.*NO_LONG_DOUBLE/,/#endif/d' < mathdef.h > mathdef.h.new
      mv mathdef.h.new mathdef.h
)

# LIB-C woes.
# We don't have the core files made yet, but generally, linking for arm needs:
# ... elf-init.o crt1.o crti.o crtbegin.o [-L] [user.o's] [gcc lb] [C lb] crtend.o crtn.o
# Unfortunately, GCC uses these during configuration tests and to make libgcc.o
# so we need them NOW, even if they are a little wrong, to make gcc.
# What they are:
# crt1.o -- from glibc's Start.S --calls libc's __libc_csu_init, __libc_csu_fini
# crti.o -- gcc's default version is no good; but libc's is.  defines prolog _init
# crtn.o -- ... ; defines function epilog _fini
# crtbegin.o and crtend.o are supplied by gcc, for constructors/destructors.
# elf-init.o -- I don't remember what it is, but it has fn's that gcc needs.
#
# so, we need to build the crt files -- and only them... as the rest can't be
# done yet. So we 'make' the crt's subdirectory.
make CFLAGS="-Os -w" ARCH=arm cross-compiling=yes csub/subdir_lib
# Manually install them in a place where the linker will find them...
cp csu/crt*.o $TARGETROOT/lib
# elf-init.o is only needed during the build of GCC.  It should be removed
# after the new gcc is made, or if it causes errors when gcc is made for
# redundant symbols.
cp csu/elf-init.o $TARGETROOT/lib
) # finished with bash subtask.  restore environment to normal.

# The .local tools we built previously are now basically useless
# I'll just move them, although you might want to remove them...
mv .local .local.eabi

# ****************************************************************************
# ----------------------------------------------------------------------------
# Build actual tools
# We must build gcc.linux.gnueabi in order for glibc programs to compile right...
# ----------------------------------------------------------------------------
# Create a clean .local directory

mkdir .local
cd .local
ln -s . usr
ln -s . local
mkdir include
mkdir lib
mkdir bin
ln -s include sys-linux
cd ..

# Rebuild the toolchain with the basic headers we just installed.

# First do bintools
# Be sure to Change the DEFAULT_EABI to version 5 before compiling gas.

mkdir build.binutils2.19.1.linux.gnueabi
cd build.binutils2.19.1.linux.gnueabi
../binutils-2.19.1/configure --target=arm-linux-gnueabi --prefix=$CROSSROOT --with-sysroot=$TARGETROOT
# Make with flags to prevent warning creep on newer GCC's compiling older code.
make CFLAGS="-O2 -w"
make install
cd ..

# !!!! Now for GCC. 

mkdir build.gcc.linux.gnueabi
cd build.gcc.linux.gnueabi
../gcc-4.2.0/configure --target=arm-linux-gnueabi --prefix=$CROSSROOT --enable-multilib --disable-libssp --enable-shared --disable-libgomp --disable-werror --disable-libmudflap --with-sysroot=$TARGETROOT 
make -j2
make install
cd ..

# Create the specs file for editing GCC's configuration if we want to...
arm-linux-gnueabi-gcc -dumpspecs > .local/arm-linux-gnueabi/lib/specs
#   Edit the specs file, and make *startfile command read:
#
#   %{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} elf-init.o%s crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}
vim .local/arm-linux-gnueabi/lib/specs
#   This edit will cause GCC to link the elf-init.o crti.o crt1.o crtn.o files (happily) from $TARGETROOT/lib where a user can easily install them.

# There are a few abused/problem header files... so fix them!
vim glibc-2.5/posix/regex_internal.h  # line 393, changed static int to 
#static reg_errcode_t  build_wcs_upper_buffer (re_string_t *pstr) internal_function;
vim .target/include/asm/unistd.h # find line 410, comment it out...
# And do a softlink to fake out an abused header...
ln -s hwcap.h .target/include/asm/procinfo.h

# Now we can finally build a true libc...
mkdir build.glibc.gnueabi

( # Enter a new shell, because path needs to be forced.
rm -rf build.glibc.gnueabi/*
cd build.glibc.gnueabi
# GLibc errors out if it thinks LD_LIBRARY_PATH is set wrong, even if it's not.
# So disable it temporarily.
export LD_LIBRARY_PATH="" 

echo "libc_cv_forced_unwind=yes" > config.cache # No crt1.o exists, yet...force
echo "libc_cv_ctors_header=yes" >> config.cache # constructor headers, yes?
echo "libc_cv_c_cleanup=yes" >> config.cache
echo "cross_compiling=yes" >> config.cache

echo "install_root=$TARGETROOT" > configparms # Where to really install target
export CFLAGS="-fgnu89-inline -D__OPTIMIZE__ -O2 "

../glibc-2.5/configure --build=i686 --host=arm-linux-gnueabi --prefix=/ --enable-kernel=2.6.23 --with-headers=$TARGETROOT/include --enable-add-ons --disable-profile --with-tls --with-__thread --cache-file=config.cache

make
make install-headers install_root=$TARGETROOT
make localedata/install-locales install_root=$TARGETROOT
) # End of subshell

OTHER TIPS

You can find the toolchain Sony used over at their Source Code Distribution Service site:

http://www.sony.net/Products/Linux/Audio/PRS-900.html

It seems sourceryg++-4.2-28armeabi.src.rpm is the compiler.

I would not recommend running the compiler on the device itself; it will be very slow.

Regarding the "Illegal instruction" issue, it's possible that your compiler is generating too new instructions, and passing -march=armv6 might just solve it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top