diff options
author | Colin Cross <ccross@android.com> | 2016-04-28 14:50:03 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2016-05-03 14:03:38 -0700 |
commit | 665dce9320c73180ccd715699a54b6e139b5d19b (patch) | |
tree | 91da5cf1540c6824784a3011b1258e04833b24b8 | |
parent | 1474741435774f15923967e50bf7531a3cc9d4f7 (diff) | |
download | build_soong-665dce9320c73180ccd715699a54b6e139b5d19b.tar.gz build_soong-665dce9320c73180ccd715699a54b6e139b5d19b.tar.bz2 build_soong-665dce9320c73180ccd715699a54b6e139b5d19b.zip |
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
-rw-r--r-- | cc/builder.go | 42 | ||||
-rw-r--r-- | cc/cc.go | 83 | ||||
-rwxr-xr-x | scripts/strip.sh | 122 |
3 files changed, 229 insertions, 18 deletions
diff --git a/cc/builder.go b/cc/builder.go index ca8bc750..10c85087 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -101,6 +101,18 @@ var ( }, "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") copyGccLib = pctx.StaticRule("copyGccLib", @@ -138,6 +150,10 @@ type builderFlags struct { nocrt bool toolchain Toolchain clang bool + + stripKeepSymbols bool + stripKeepMiniDebugInfo bool + stripAddGnuDebuglink bool } // 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, flags builderFlags, outputFile common.WritablePath) { @@ -434,10 +434,16 @@ type InstallerProperties struct { Relative_install_path string } +type StripProperties struct { + Strip struct { + None bool + Keep_symbols bool + } +} + type UnusedProperties struct { Native_coverage *bool Required []string - Strip string Tags []string } @@ -1441,6 +1447,7 @@ func (library *libraryCompiler) compile(ctx ModuleContext, flags Flags, deps Pat type libraryLinker struct { baseLinker flagExporter + stripper Properties LibraryLinkerProperties @@ -1465,7 +1472,8 @@ func (library *libraryLinker) props() []interface{} { return append(props, &library.Properties, &library.dynamicProperties, - &library.flagExporter.Properties) + &library.flagExporter.Properties, + &library.stripper.StripProperties) } 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, 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 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 = append(sharedLibs, deps.LateSharedLibs...) TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, 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, @@ -1746,6 +1763,7 @@ func (*objectLinker) installable() bool { type binaryLinker struct { baseLinker + stripper Properties BinaryLinkerProperties @@ -1755,7 +1773,10 @@ type binaryLinker struct { var _ linker = (*binaryLinker)(nil) 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 { @@ -1906,18 +1927,12 @@ func (binary *binaryLinker) flags(ctx ModuleContext, flags Flags) Flags { func (binary *binaryLinker) link(ctx ModuleContext, 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() { 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 @@ -1928,9 +1943,24 @@ func (binary *binaryLinker) link(ctx ModuleContext, 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, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true, - flagsToBuilderFlags(flags), outputFile) + builderFlags, outputFile) return ret } @@ -1939,6 +1969,22 @@ func (binary *binaryLinker) HostToolPath() common.OptionalPath { 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) { if m, ok := mctx.Module().(*Module); ok { if test, ok := m.linker.(*testLinker); ok { @@ -2155,6 +2201,7 @@ func defaultsFactory() (blueprint.Module, []interface{}) { &UnusedProperties{}, &StlProperties{}, &SanitizeProperties{}, + &StripProperties{}, } _, propertyStructs = common.InitAndroidArchModule(module, common.HostAndDeviceDefault, diff --git a/scripts/strip.sh b/scripts/strip.sh new file mode 100755 index 00000000..5c43028c --- /dev/null +++ b/scripts/strip.sh @@ -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 |