Support stripping shared libraries and binaries

Strip all shared libraries and binaries by default.  Use a shell script
to wrap the long sequences of commands needed by some strip variants.

Change-Id: I465bf7cc48330913e60e24762fd55fa2a7731c26
This commit is contained in:
Colin Cross
2016-04-28 14:50:03 -07:00
parent 1474741435
commit 665dce9320
3 changed files with 229 additions and 18 deletions

View File

@@ -101,6 +101,18 @@ var (
}, },
"objcopyCmd", "prefix") "objcopyCmd", "prefix")
stripPath = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh")
strip = pctx.StaticRule("strip",
blueprint.RuleParams{
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
Command: "CROSS_COMPILE=$crossCompile $stripPath ${args} -i ${in} -o ${out} -d ${out}.d",
CommandDeps: []string{"$stripPath"},
Description: "strip $out",
},
"args", "crossCompile")
copyGccLibPath = pctx.SourcePathVariable("copyGccLibPath", "build/soong/scripts/copygcclib.sh") copyGccLibPath = pctx.SourcePathVariable("copyGccLibPath", "build/soong/scripts/copygcclib.sh")
copyGccLib = pctx.StaticRule("copyGccLib", copyGccLib = pctx.StaticRule("copyGccLib",
@@ -138,6 +150,10 @@ type builderFlags struct {
nocrt bool nocrt bool
toolchain Toolchain toolchain Toolchain
clang bool clang bool
stripKeepSymbols bool
stripKeepMiniDebugInfo bool
stripAddGnuDebuglink bool
} }
// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
@@ -397,6 +413,32 @@ func TransformBinaryPrefixSymbols(ctx common.AndroidModuleContext, prefix string
}) })
} }
func TransformStrip(ctx common.AndroidModuleContext, inputFile common.Path,
outputFile common.WritablePath, flags builderFlags) {
crossCompile := gccCmd(flags.toolchain, "")
args := ""
if flags.stripAddGnuDebuglink {
args += " --add-gnu-debuglink"
}
if flags.stripKeepMiniDebugInfo {
args += " --keep-mini-debug-info"
}
if flags.stripKeepSymbols {
args += " --keep-symbols"
}
ctx.ModuleBuild(pctx, common.ModuleBuildParams{
Rule: strip,
Output: outputFile,
Input: inputFile,
Args: map[string]string{
"crossCompile": crossCompile,
"args": args,
},
})
}
func CopyGccLib(ctx common.AndroidModuleContext, libName string, func CopyGccLib(ctx common.AndroidModuleContext, libName string,
flags builderFlags, outputFile common.WritablePath) { flags builderFlags, outputFile common.WritablePath) {

View File

@@ -434,10 +434,16 @@ type InstallerProperties struct {
Relative_install_path string Relative_install_path string
} }
type StripProperties struct {
Strip struct {
None bool
Keep_symbols bool
}
}
type UnusedProperties struct { type UnusedProperties struct {
Native_coverage *bool Native_coverage *bool
Required []string Required []string
Strip string
Tags []string Tags []string
} }
@@ -1441,6 +1447,7 @@ func (library *libraryCompiler) compile(ctx ModuleContext, flags Flags, deps Pat
type libraryLinker struct { type libraryLinker struct {
baseLinker baseLinker
flagExporter flagExporter
stripper
Properties LibraryLinkerProperties Properties LibraryLinkerProperties
@@ -1465,7 +1472,8 @@ func (library *libraryLinker) props() []interface{} {
return append(props, return append(props,
&library.Properties, &library.Properties,
&library.dynamicProperties, &library.dynamicProperties,
&library.flagExporter.Properties) &library.flagExporter.Properties,
&library.stripper.StripProperties)
} }
func (library *libraryLinker) flags(ctx ModuleContext, flags Flags) Flags { func (library *libraryLinker) flags(ctx ModuleContext, flags Flags) Flags {
@@ -1554,9 +1562,6 @@ func (library *libraryLinker) linkStatic(ctx ModuleContext,
func (library *libraryLinker) linkShared(ctx ModuleContext, func (library *libraryLinker) linkShared(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles common.Paths) common.Path { flags Flags, deps PathDeps, objFiles common.Paths) common.Path {
outputFile := common.PathForModuleOut(ctx,
ctx.ModuleName()+library.Properties.VariantName+flags.Toolchain.ShlibSuffix())
var linkerDeps common.Paths var linkerDeps common.Paths
versionScript := common.OptionalPathForModuleSrc(ctx, library.Properties.Version_script) versionScript := common.OptionalPathForModuleSrc(ctx, library.Properties.Version_script)
@@ -1595,14 +1600,26 @@ func (library *libraryLinker) linkShared(ctx ModuleContext,
} }
} }
fileName := ctx.ModuleName() + library.Properties.VariantName + flags.Toolchain.ShlibSuffix()
outputFile := common.PathForModuleOut(ctx, fileName)
ret := outputFile
builderFlags := flagsToBuilderFlags(flags)
if library.stripper.needsStrip(ctx) {
strippedOutputFile := outputFile
outputFile = common.PathForModuleOut(ctx, "unstripped", fileName)
library.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
}
sharedLibs := deps.SharedLibs sharedLibs := deps.SharedLibs
sharedLibs = append(sharedLibs, deps.LateSharedLibs...) sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, TransformObjToDynamicBinary(ctx, objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
linkerDeps, deps.CrtBegin, deps.CrtEnd, false, flagsToBuilderFlags(flags), outputFile) linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
return outputFile return ret
} }
func (library *libraryLinker) link(ctx ModuleContext, func (library *libraryLinker) link(ctx ModuleContext,
@@ -1746,6 +1763,7 @@ func (*objectLinker) installable() bool {
type binaryLinker struct { type binaryLinker struct {
baseLinker baseLinker
stripper
Properties BinaryLinkerProperties Properties BinaryLinkerProperties
@@ -1755,7 +1773,10 @@ type binaryLinker struct {
var _ linker = (*binaryLinker)(nil) var _ linker = (*binaryLinker)(nil)
func (binary *binaryLinker) props() []interface{} { func (binary *binaryLinker) props() []interface{} {
return append(binary.baseLinker.props(), &binary.Properties) return append(binary.baseLinker.props(),
&binary.Properties,
&binary.stripper.StripProperties)
} }
func (binary *binaryLinker) buildStatic() bool { func (binary *binaryLinker) buildStatic() bool {
@@ -1906,18 +1927,12 @@ func (binary *binaryLinker) flags(ctx ModuleContext, flags Flags) Flags {
func (binary *binaryLinker) link(ctx ModuleContext, func (binary *binaryLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles common.Paths) common.Path { flags Flags, deps PathDeps, objFiles common.Paths) common.Path {
outputFile := common.PathForModuleOut(ctx, binary.getStem(ctx)+flags.Toolchain.ExecutableSuffix()) fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
outputFile := common.PathForModuleOut(ctx, fileName)
ret := outputFile
if ctx.HostOrDevice().Host() { if ctx.HostOrDevice().Host() {
binary.hostToolPath = common.OptionalPathForPath(outputFile) binary.hostToolPath = common.OptionalPathForPath(outputFile)
} }
ret := outputFile
if binary.Properties.Prefix_symbols != "" {
afterPrefixSymbols := outputFile
outputFile = common.PathForModuleOut(ctx, binary.getStem(ctx)+".intermediate")
TransformBinaryPrefixSymbols(ctx, binary.Properties.Prefix_symbols, outputFile,
flagsToBuilderFlags(flags), afterPrefixSymbols)
}
var linkerDeps common.Paths var linkerDeps common.Paths
@@ -1928,9 +1943,24 @@ func (binary *binaryLinker) link(ctx ModuleContext,
flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker) flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
} }
builderFlags := flagsToBuilderFlags(flags)
if binary.stripper.needsStrip(ctx) {
strippedOutputFile := outputFile
outputFile = common.PathForModuleOut(ctx, "unstripped", fileName)
binary.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
}
if binary.Properties.Prefix_symbols != "" {
afterPrefixSymbols := outputFile
outputFile = common.PathForModuleOut(ctx, "unprefixed", fileName)
TransformBinaryPrefixSymbols(ctx, binary.Properties.Prefix_symbols, outputFile,
flagsToBuilderFlags(flags), afterPrefixSymbols)
}
TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, deps.StaticLibs, TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
flagsToBuilderFlags(flags), outputFile) builderFlags, outputFile)
return ret return ret
} }
@@ -1939,6 +1969,22 @@ func (binary *binaryLinker) HostToolPath() common.OptionalPath {
return binary.hostToolPath return binary.hostToolPath
} }
type stripper struct {
StripProperties StripProperties
}
func (stripper *stripper) needsStrip(ctx ModuleContext) bool {
return !ctx.AConfig().EmbeddedInMake() && !stripper.StripProperties.Strip.None
}
func (stripper *stripper) strip(ctx ModuleContext, in, out common.ModuleOutPath,
flags builderFlags) {
flags.stripKeepSymbols = stripper.StripProperties.Strip.Keep_symbols
// TODO(ccross): don't add gnu debuglink for user builds
flags.stripAddGnuDebuglink = true
TransformStrip(ctx, in, out, flags)
}
func testPerSrcMutator(mctx common.AndroidBottomUpMutatorContext) { func testPerSrcMutator(mctx common.AndroidBottomUpMutatorContext) {
if m, ok := mctx.Module().(*Module); ok { if m, ok := mctx.Module().(*Module); ok {
if test, ok := m.linker.(*testLinker); ok { if test, ok := m.linker.(*testLinker); ok {
@@ -2155,6 +2201,7 @@ func defaultsFactory() (blueprint.Module, []interface{}) {
&UnusedProperties{}, &UnusedProperties{},
&StlProperties{}, &StlProperties{},
&SanitizeProperties{}, &SanitizeProperties{},
&StripProperties{},
} }
_, propertyStructs = common.InitAndroidArchModule(module, common.HostAndDeviceDefault, _, propertyStructs = common.InitAndroidArchModule(module, common.HostAndDeviceDefault,

122
scripts/strip.sh Executable file
View File

@@ -0,0 +1,122 @@
#!/bin/bash -e
# Script to handle the various ways soong may need to strip binaries
# Inputs:
# Environment:
# CROSS_COMPILE: prefix added to readelf, objcopy tools
# Arguments:
# -o ${file}: output file (required)
# -d ${file}: deps file (required)
# --keep-symbols
# --keep-mini-debug-info
# --add-gnu-debuglink
OPTSTRING=d:i:o:-:
usage() {
cat <<EOF
Usage: strip.sh [options] -i in-file -o out-file -d deps-file
Options:
--keep-symbols Keep symbols in out-file
--keep-mini-debug-info Keep compressed debug info in out-file
--add-gnu-debuglink Add a gnu-debuglink section to out-file
EOF
exit 1
}
do_strip() {
"${CROSS_COMPILE}strip" --strip-all "${infile}" -o "${outfile}.tmp"
}
do_strip_keep_symbols() {
"${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" \
`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {print "-R " $2}' | xargs`
}
do_strip_keep_mini_debug_info() {
"${CROSS_COMPILE}nm" -D "${infile}" --format=posix --defined-only | awk '{ print $$1 }' | sort >"${outfile}.dynsyms"
"${CROSS_COMPILE}nm" "${infile}" --format=posix --defined-only | awk '{ if ($$2 == "T" || $$2 == "t" || $$2 == "D") print $$1 }' | sort > "${outfile}.funcsyms"
comm -13 "${outfile}.dynsyms" "${outfile}.funcsyms" > "${outfile}.keep_symbols"
"${CROSS_COMPILE}objcopy" --only-keep-debug "${infile}" "${outfile}.debug"
"${CROSS_COMPILE}objcopy" --rename-section .debug_frame=saved_debug_frame "${outfile}.debug" "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}strip" --strip-all -R .comment "${infile}" -o "${outfile}.tmp"
rm -f "${outfile}.mini_debuginfo.xz"
xz "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo.xz"
}
do_add_gnu_debuglink() {
"${CROSS_COMPILE}objcopy" --add-gnu-debuglink="${infile}" "${outfile}.tmp"
}
while getopts $OPTSTRING opt; do
case "$opt" in
d) depsfile="${OPTARG}" ;;
i) infile="${OPTARG}" ;;
o) outfile="${OPTARG}" ;;
-)
case "${OPTARG}" in
keep-symbols) keep_symbols=true ;;
keep-mini-debug-info) keep_mini_debug_info=true ;;
add-gnu-debuglink) add_gnu_debuglink=true ;;
*) echo "Unknown option --${OPTARG}"; usage ;;
esac;;
?) usage ;;
*) echo "'${opt}' '${OPTARG}'"
esac
done
if [ -z "${infile}" ]; then
echo "-i argument is required"
usage
fi
if [ -z "${outfile}" ]; then
echo "-o argument is required"
usage
fi
if [ -z "${depsfile}" ]; then
echo "-d argument is required"
usage
fi
if [ ! -z "${keep_symbols}" -a ! -z "${keep_mini_debug_info}" ]; then
echo "--keep-symbols and --keep-mini-debug-info cannot be used together"
usage
fi
if [ ! -z "${add_gnu_debuglink}" -a ! -z "${keep_mini_debug_info}" ]; then
echo "--add-gnu-debuglink cannot be used with --keep-mini-debug-info"
usage
fi
rm -f "${outfile}.tmp"
if [ ! -z "${keep_symbols}" ]; then
do_strip_keep_symbols
elif [ ! -z "${keep_mini_debug_info}" ]; then
do_strip_keep_mini_debug_info
else
do_strip
fi
if [ ! -z "${add_gnu_debuglink}" ]; then
do_add_gnu_debuglink
fi
rm -f "${outfile}"
mv "${outfile}.tmp" "${outfile}"
cat <<EOF > "${depsfile}"
${outfile}: \
${infile} \
${CROSS_COMPILE}nm \
${CROSS_COMPILE}objcopy \
${CROSS_COMPILE}readelf \
${CROSS_COMPILE}strip
EOF