#!/bin/ksh
# Shell script to remake an executable or shared object file
#
# Acknowlegement:  Author wished to acknowlege the assistance
# provided to him by Mr Cliff Hoagland, AIX SW developer.
# His technical expertise was critical in the creation of the
# AIXpert article and this shell script.
#
#  Usage:
 
if [ $# = 0 ]
then 
        whoami=$(basename $0)
        echo ""
        echo "Usage:    $whoami filename <updated_objects>
        echo ""
        echo "Relinks the executable filename"
        echo "Output is filename.NEW"
        echo "And will be placed in the current directory."
        echo ""
        echo "Temporary files in current directory are:"
        echo "   ld.imp ld.impexp ld.exp ld.exps"
        echo "   Deleted at end of the link"
        echo ""
        exit 101
fi
 
#
# First command line operand is the file being rebound.
filename=$1
shift
# 
# User specified objects to update.
ldobjsu="$*"
#
# Compiler (xlc) default ldflags (user may want to alter some of these)
ldflagsc="-bh:4 -H512 -T512"
#
# Script generated ld() flags
#  --- appended throughout this script
#  General ld flags
ldflags=""
#  Import and export ld flags
ldimpexp=""
#
#       Determine type of object file to set additional ld flags
#
# Check that the specified file actually exists:
if [ -s $filename ]
then
#       Set for new output file to go to current directory.
        fileout=$(basename $filename)
else
#       EXIT IF the file does not exist
        echo "$filename: File does not exist or is of zero length"
        exit 20
fi
#
# Check if the specified file is an archive - unable to relink an archive.
# Determined from the XCOFF header record flags
dump -ov $filename 2>/dev/null | fgrep "$filename[" >/dev/null
rc=$?
#
# EXIT IF file is an archive, the user must extract single executable
if [ $rc -eq 0 ]
then
        echo "$filename: File is an archive file"
        echo "Extract the executables that you wish to process."
        exit 21
fi
#
# Check to make sure the specified file is already executable.
# Determined from the XCOFF header record flags
dump -ov $filename 2>/dev/null | fgrep EXEC >/dev/null
rc=$?
# EXIT IF object file is not already an executable
if [ $rc -ne 0 ]
then
        echo "$filename: File is not an xcoff executable."
        exit 22
fi
#
# IS it a regular executable or a shared object file
# Determined from the XCOFF header record flags
 
dump -ov $filename | fgrep SHROBJ >/dev/null
rc=$?
if [ $rc -ne 0 ]
then
        echo "$filename: File is a regular xcoff executable"
else
        echo "$filename: File is a shared object xcoff executable"
#       Update ldflags to re-make shared object file
#       These are REQUIRED for remaking the shared object!
        ldflags="$ldflags -bnso -bM:SRE"
fi
#
# Determine the LIBPATH information from XCOFF loader section.
#   Must cut "/lib:/usr/lib" or "/usr/lib:/lib" from the the -L flags
#   These are the defaults (depending on version) and are always added
#   NOTE: A long LIBPATH may get truncated here.
Lflag=`dump -Hp $filename | fgrep "/usr/lib" | untab | cut -c8-256 \
        | sed '
s/ //g
/[:]\{0,1\}\/lib:\/usr\/lib[:]\{0,1\}$/s///
/[:]\{0,1\}\/usr\/lib:\/lib[:]\{0,1\}$/s///
s/.*/-L&/
s/-L$//
' `
#
# Determine the entry point name from XCOFF loader section.
#
echo "Determining module entry point name."
ENTNAME=`dump -Tv $filename | untab | fgrep " ENTpt " | cut -c68-200`
if [ $ENTNAME ] 
   then 
       ENTPT=-e$ENTNAME
       echo "Entry name = " $ENTNAME
   else
        echo "No entry point name found in module."
   fi
 
#
# Build the IMPORTS List, EXPORTS List, and IMPORT/EXPORT List
# Information extracted fromt the XCOFF loader section
#
# IMPORTS first
echo "Creating IMPORTS File"
dump -HTv $filename | untab | fgrep " IMP " | sort +6 \
        | cut -c53-200 \
        | awk '{ print "#!", $1, "\n", $2 }' \
        | sed 's/\[noIMid\]//'  > ld.imp
if [ -s ld.imp ]
then
        ldimpexp="$ldimpexp -bI:ld.imp"
fi
#
# ##### Below changes occurrances of "unix" to "/unix"
# ##### A general problem that path_names not included in the names
# #####  for imports.
echo "Creating IMPORTS/EXPORTS File"
dump -HTv $filename | untab | fgrep " ImpExp " | sort +6 \
        | cut -c53-200 \
        | awk '{ print "#!", $1, "\n", $2 }' \
        | sed 's!unix!/unix!' \
        | sed 's/\[noIMid\]//'  > ld.impexp
if [ -s ld.impexp ]
then
        ldimpexp="$ldimpexp -bI:ld.impexp -bE:ld.impexp"
fi
#
echo "Creating EXPORTS File"
#       Write "#!" as first record
echo "#!" > ld.exp
#
dump -HTv $filename | untab | fgrep " EXP " | sort +6 \
        | tee ld.exps | cut -c68-200 >> ld.exp
if [ -s ld.exps ]
then
        ldimpexp="$ldimpexp -bE:ld.exp"
fi
 
#       Compiler default ldflags
echo "Default (xlc) ldflagsc=$ldflagsc"
#       Generated ldflags
echo "Generated ldflags=$ldflags"
#       User supplied ldflags
echo "User objects specified =$ldobjsu"
#     Library Flags
echo "Libpath Lflag=$Lflag"
#       IMPORT/EXPORT flags
echo "Imports/exports ldimpexp=$ldimpexp"
#       Output generating.
echo "Output file = $fileout.NEW"
 
##### May want to modify this to allow for updated libraries to be included.
set -x
ld  -o $fileout.NEW $ldobjsu $filename $ldflagsc $ldflags $ENTPT \
  $ldflagsu  $Lflag  $ldimpexp
 
ldrc=$?
#
echo "ld() return code = $ldrc"
#
# delete the intermediate work files
rm -f ld.imp ld.impexp ld.exp
rm -f ld.exps
exit $ldrc
