What's new

HOWTO: Relocate ARM ELF binaries to run from the router /jffs folder

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

ASAT

Senior Member
I discovered this simple trick, if you need a quick and dirty method to run Entware-ng or Optware-ng programs directly off your router /jffs folder. The patchelf program is capable of changing the run path and library path inside the ELF header of an ARM binary executable image. For example, it's lets you change /opt/lib to /jffs/lib inside an ARM executable program or library, so you can file copy the program from /opt to /jffs and it will run from /jffs without giving a missing library error.

HOW: Cross-compile the patchelf program on your Asuswrt-Merlin build box.
Code:
cd ~
wget http://nixos.org/releases/patchelf/patchelf-0.8/patchelf-0.8.tar.gz
tar xzvf patchelf-0.8.tar.gz
cd patchelf-0.8

./configure '--host=arm-brcm-linux-uclibcgnueabi' '--build=' CFLAGS="-static -ffunction-sections -fdata-sections -O3 -pipe -march=armv7-a -mtune=cortex-a9 -fno-caller-saves -mfloat-abi=soft -Wall -fPIC -std=gnu99" CPPFLAGS="-static -ffunction-sections -fdata-sections -O3 -pipe -march=armv7-a -mtune=cortex-a9 -fno-caller-saves -mfloat-abi=soft -Wall -fPIC -std=gnu99" CXXFLAGS="-static -ffunction-sections -fdata-sections -O3 -pipe -march=armv7-a -mtune=cortex-a9 -fno-caller-saves -mfloat-abi=soft -Wall -fPIC -std=gnu99" LDFLAGS="-Wl,--gc-sections"

make

arm-brcm-linux-uclibcgnueabi-strip --strip-all ./src/patchelf

That's it. Now copy the patchelf program to the router /jffs folder.

I have tested it with only little programs and it seems to work fine.
 
Last edited:
This tool helps solving the wred segfault issue in a cleaner way, which I like very much. Thank you, ASAT.

Now I have the firmware running in NTPL except wred which lives in its own little LinuxThread world.

A skeleton How-To
  1. Configure & make patchelf for Linux PC ('cos we operate surgery on PC)
  2. Backup ld-uClibc.so.0,libc.so.0,libel.so.0,libpthread.so.0 from stock Merlin firmware to your favourite storage
  3. Build your own firmware with the NPTL toolchains.
  4. mkdir -p router/arm-uclibc/target/lib/uClibc-0.99.32.1
  5. Copy the backup from Step 2 to the new directory of Step 4
  6. patchelf --set-interpreter /lib/uClibc-0.99.32.1/ld-uClibc.so.0 router/arm-uclibc/target/usr/sbin/wred
  7. make image
Now find the image and flash it to your beloved Asus router. Enjoy!
 
I've had some success with copying Entware-ng programs from /opt to /jffs. Maybe you use it for cryptsetup? Think about it.

Example

# install an entware-ng program
opkg update && opkg install cryptsetup

# run my script to copy the ARM ELF binary from /opt to /jffs
/jffs/home/cpopt /opt/sbin/cryptsetup

# remove the original program, optional
opkg remove cryptsetup

# run the program from it's new location
/jffs/entware-ng/opt/sbin/cryptsetup --help


My script copies Entware-ng programs from /opt to /jffs and automatically copies the dependent libraries and then updates the ELF headers to reflect the new home.

/jffs/home/cpopt
Code:
#!/bin/sh
local OBJDUMP="/opt/bin/objdump"
local PATCHELF="/jffs/bin/patchelf"
local OLDROOT="/opt"
local NEWROOT="/jffs/entware-ng/opt"

local RET_LIB_PATH
find_library()
{
  local LIB_FILE="$1"

  local LIB_PATH="$FOLDER_LIB/$LIB_FILE"
  if [ -e "$LIB_PATH" ]; then
    RET_LIB_PATH="$LIB_PATH"
    return 0
  else
    local LIB_PATH="$FOLDER_LIB_USR/$LIB_FILE"
    if [ -e "$LIB_PATH" ]; then
      RET_LIB_PATH="$LIB_PATH"
      return 0
    fi
  fi

  return 1
}

walk_depends()
{
  local FILE_PATH="$1"

  if [ "${FILE_PATHS#*$FILE_PATH}" == "$FILE_PATHS" ]; then
    FILE_PATHS="$FILE_PATHS $FILE_PATH"
  fi

  local LIBS="$($OBJDUMP -p $FILE_PATH | /bin/grep "  NEEDED" | /usr/bin/cut -f18 -d' ')"

  local LIB_FILE
  for LIB_FILE in $LIBS
  do
    find_library "$LIB_FILE"
    if [ $? -eq 0 ]; then
      walk_depends "$RET_LIB_PATH"
    else
      /bin/echo "${LIB_FILE} *** missing ***"
      ERROR=1
    fi
  done

  return 0
}

copy_files()
{
  local OLD_FILE_PATH
  for OLD_FILE_PATH in $FILE_PATHS
  do
    local NEW_FILE_PATH="${NEWROOT}${OLD_FILE_PATH#${OLDROOT}*}"
    local NEW_FOLDER="${NEW_FILE_PATH%/*}"
    /bin/mkdir -p "$NEW_FOLDER"

    /bin/echo "copying $OLD_FILE_PATH to $NEW_FILE_PATH"

    /bin/cp -p "$OLD_FILE_PATH" "$NEW_FILE_PATH"

    local OLD_INTERP="$($PATCHELF --print-interpreter $OLD_FILE_PATH 2> /dev/null)"
    if [ ! -z "$OLD_INTERP" ]; then
      local NEW_INTERP="${NEWROOT}${OLD_INTERP#${OLDROOT}*}"
      $PATCHELF --set-interpreter $NEW_INTERP $NEW_FILE_PATH
    fi

    local OLD_RPATH="$($PATCHELF --print-rpath $OLD_FILE_PATH 2> /dev/null)"
    if [ ! -z "$OLD_RPATH" ]; then
      local NEW_RPATH="${NEWROOT}${OLD_RPATH#${OLDROOT}*}"
      $PATCHELF --set-rpath $NEW_RPATH $NEW_FILE_PATH
    fi
  done
}

local FILE_PATH="$1"
if [ -e "$FILE_PATH" ]; then

  if [ "${FILE_PATH#${OLDROOT}*}" == "$FILE_PATH" ]; then
    /bin/echo "Base path is not $OLDROOT"
    return 1
  fi

  if [ ! -f "$OBJDUMP" ]; then
    /bin/echo "The objdump program is missing.  Please install it."
    /bin/echo "Example:"
    /bin/echo "$ opkg update"
    /bin/echo "$ opkg install objdump"
    return 1
  fi

  if [ ! -f "$PATCHELF" ]; then
    /bin/echo "The patchelf program is missing.  Please install it."
    return 1
  fi

  local ERROR=0
  local FILE_PATHS=""
  local OLD_INTERP="$($PATCHELF --print-interpreter $FILE_PATH)"
  local FOLDER_LIB="${OLD_INTERP%/*}"
  local FOLDER_LIB_USR="${FOLDER_LIB/lib/usr/lib}"

  walk_depends "$FILE_PATH"

  if [ $ERROR == 0 ]; then
    copy_files
  fi

else

  /bin/echo
  /bin/echo "Automatically relocate ARM ELF binaries and dependencies from $OLDROOT to $NEWROOT"
  /bin/echo "Usage:  ${0##*/} file-path"
  /bin/echo
  /bin/echo "File not found."
  /bin/echo
  return 1

fi


My script requires the objdump program from Entware-ng.

opkg update
opkg install objdump



The patchelf program is required as well.
 
Last edited:
Just for fun. This script explodes the dependent libraries of a program into a tree view. It is simple analysis tool. You must have the two required programs installed (objdump and patchelf) and put their pathnames in the variables of the script.

/jffs/home/depends
Code:
#!/bin/sh
local FILE_PATH="$1"
local OBJDUMP="/opt/bin/objdump"
local PATCHELF="/jffs/bin/patchelf"

local RET_LIB_PATH
find_library()
{
  local LIB_FILE="$1"

  local LIB_PATH="$FOLDER_LIB/$LIB_FILE"
  if [ -e "$LIB_PATH" ]; then
    RET_LIB_PATH="$LIB_PATH"
    return 0
  else
    local LIB_PATH="$FOLDER_LIB_USR/$LIB_FILE"
    if [ -e "$LIB_PATH" ]; then
      RET_LIB_PATH="$LIB_PATH"
      return 0
    fi
  fi

  return 1
}

walk_depends()
{
  local FILE_PATH="$1"
  local TREE_LINES="$2"
  local TREE_LINES_NEXT="$3"

  /bin/echo "${TREE_LINES}${TREE_LINES_NEXT}${FILE_PATH}"

  if [ "$TREE_LINES_NEXT" == "$LINE1" ]; then
    local TREE_LINES=${TREE_LINES}"$LINE3"
  elif [ "$TREE_LINES_NEXT" == "$LINE2" ]; then
    local TREE_LINES=${TREE_LINES}"$LINE4"
  fi

  local LIBS="$($OBJDUMP -p $FILE_PATH | /bin/grep "  NEEDED" | /usr/bin/cut -f18 -d' ')"
  local NUM_LIBS=$(/bin/echo $LIBS | /usr/bin/wc -w)

  local L=0
  local LIB_FILE
  for LIB_FILE in ${LIBS}
  do
    let local L++
    if [ $L -lt $NUM_LIBS ]; then
      local TREE_LINES_NEXT="$LINE1"
    else
      local TREE_LINES_NEXT="$LINE2"
    fi

    find_library "$LIB_FILE"
    if [ $? -eq 0 ]; then
      walk_depends "$RET_LIB_PATH" "$TREE_LINES" "$TREE_LINES_NEXT"
    else
      /bin/echo "${TREE_LINES}${TREE_LINES_NEXT}${LIB_FILE} *** missing ***"
    fi
  done

  return 0
}

local LINE1="├─"
local LINE2="└─"
local LINE3="│ "
local LINE4="  "

if [ -e "$FILE_PATH" ]; then
  local PATH_INTERP="$($PATCHELF --print-interpreter $FILE_PATH)"
  local FOLDER_LIB="${PATH_INTERP%/*}"
  local FOLDER_LIB_USR="${FOLDER_LIB/lib/usr/lib}"

  walk_depends "$FILE_PATH"
else
  echo "File not found"
fi



Sample output

# /jffs/home/depends /opt/sbin/cryptsetup

Code:
/opt/sbin/cryptsetup
├─/opt/lib/libcryptsetup.so.4
│ ├─/opt/lib/libuuid.so.1
│ │ ├─/opt/lib/libgcc_s.so.1
│ │ │ └─/opt/lib/libc.so.6
│ │ │   └─/opt/lib/ld-linux.so.3
│ │ └─/opt/lib/libc.so.6
│ │   └─/opt/lib/ld-linux.so.3
│ ├─/opt/lib/libdevmapper.so.1.02
│ │ ├─/opt/lib/libuuid.so.1
│ │ │ ├─/opt/lib/libgcc_s.so.1
│ │ │ │ └─/opt/lib/libc.so.6
│ │ │ │   └─/opt/lib/ld-linux.so.3
│ │ │ └─/opt/lib/libc.so.6
│ │ │   └─/opt/lib/ld-linux.so.3
│ │ ├─/opt/lib/libm.so.6
│ │ │ ├─/opt/lib/libc.so.6
│ │ │ │ └─/opt/lib/ld-linux.so.3
│ │ │ └─/opt/lib/ld-linux.so.3
│ │ ├─/opt/lib/libgcc_s.so.1
│ │ │ └─/opt/lib/libc.so.6
│ │ │   └─/opt/lib/ld-linux.so.3
│ │ └─/opt/lib/libc.so.6
│ │   └─/opt/lib/ld-linux.so.3
│ ├─/opt/lib/libgcrypt.so.20
│ │ ├─/opt/lib/libgpg-error.so.0
│ │ │ ├─/opt/lib/libgcc_s.so.1
│ │ │ │ └─/opt/lib/libc.so.6
│ │ │ │   └─/opt/lib/ld-linux.so.3
│ │ │ └─/opt/lib/libc.so.6
│ │ │   └─/opt/lib/ld-linux.so.3
│ │ ├─/opt/lib/libgcc_s.so.1
│ │ │ └─/opt/lib/libc.so.6
│ │ │   └─/opt/lib/ld-linux.so.3
│ │ └─/opt/lib/libc.so.6
│ │   └─/opt/lib/ld-linux.so.3
│ ├─/opt/lib/libgpg-error.so.0
│ │ ├─/opt/lib/libgcc_s.so.1
│ │ │ └─/opt/lib/libc.so.6
│ │ │   └─/opt/lib/ld-linux.so.3
│ │ └─/opt/lib/libc.so.6
│ │   └─/opt/lib/ld-linux.so.3
│ └─/opt/lib/libc.so.6
│   └─/opt/lib/ld-linux.so.3
├─/opt/lib/libpopt.so.0
│ ├─/opt/lib/libgcc_s.so.1
│ │ └─/opt/lib/libc.so.6
│ │   └─/opt/lib/ld-linux.so.3
│ └─/opt/lib/libc.so.6
│   └─/opt/lib/ld-linux.so.3
└─/opt/lib/libc.so.6
  └─/opt/lib/ld-linux.so.3
 
Last edited:
Similar threads
Thread starter Title Forum Replies Date
D Yet another question about VLANs (any HowTo recommended?) Asuswrt-Merlin 24

Similar threads

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top