From 49b53d5c7cb4aa622fcf5fe3cf9d7bc128c5de23 Mon Sep 17 00:00:00 2001 From: Pirama Arumuga Nainar Date: Wed, 4 Oct 2017 16:47:29 -0700 Subject: [PATCH] Explicitly link the profile runtime during PGO Bug: http://b/65598278 The profile runtime depends on libgcc for some symbols (only under some circumstances - armv5, ndk r14, static executables). Since Android build passes -nostdlib and adds libgcc manually, the profile runtime gets passed to the linker later than libgcc. Instead, explicitly add the profile runtime to the linker command (and pass one other flag added by the clang driver to the link). Test: Build a library with profile instrumentation that otherwise fails instrumented build. Change-Id: I24b34cebd2c3bb6a540f8f4c465ace1be4eb90f3 Signed-off-by: Pirama Arumuga Nainar --- cc/cc.go | 6 ++++++ cc/config/toolchain.go | 4 ++++ cc/pgo.go | 47 +++++++++++++++++++++++++++++------------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/cc/cc.go b/cc/cc.go index b4b70ed51..4f10a115d 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -673,6 +673,12 @@ func (c *Module) deps(ctx DepsContext) Deps { if c.compiler != nil { deps = c.compiler.compilerDeps(ctx, deps) } + // Add the PGO dependency (the clang_rt.profile runtime library), which + // sometimes depends on symbols from libgcc, before libgcc gets added + // in linkerDeps(). + if c.pgo != nil { + deps = c.pgo.deps(ctx, deps) + } if c.linker != nil { deps = c.linker.linkerDeps(ctx, deps) } diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go index d62ebe465..796ccfb66 100644 --- a/cc/config/toolchain.go +++ b/cc/config/toolchain.go @@ -233,6 +233,10 @@ func ThreadSanitizerRuntimeLibrary(t Toolchain) string { return SanitizerRuntimeLibrary(t, "tsan") } +func ProfileRuntimeLibrary(t Toolchain) string { + return SanitizerRuntimeLibrary(t, "profile") +} + func ToolPath(t Toolchain) string { if p := t.ToolPath(); p != "" { return p diff --git a/cc/pgo.go b/cc/pgo.go index f9c8bbf93..5d1c58a9d 100644 --- a/cc/pgo.go +++ b/cc/pgo.go @@ -19,6 +19,7 @@ import ( "strings" "android/soong/android" + "android/soong/cc/config" ) var ( @@ -50,25 +51,38 @@ type pgo struct { Properties PgoProperties } +func (props *PgoProperties) isInstrumentation() bool { + return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true +} + +func (props *PgoProperties) isSampling() bool { + return props.Pgo.Sampling != nil && *props.Pgo.Sampling == true +} + func (pgo *pgo) props() []interface{} { return []interface{}{&pgo.Properties} } -func (pgo *pgo) profileGatherFlags(ctx ModuleContext) string { - if *pgo.Properties.Pgo.Instrumentation { - return profileInstrumentFlag +func (pgo *pgo) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { + if pgo.Properties.isInstrumentation() { + flags.CFlags = append(flags.CFlags, profileInstrumentFlag) + // The profile runtime is added below in deps(). Add the below + // flag, which is the only other link-time action performed by + // the Clang driver during link. + flags.LdFlags = append(flags.LdFlags, "-u__llvm_profile_runtime") } - if *pgo.Properties.Pgo.Sampling { - return profileSamplingFlag + if pgo.Properties.isSampling() { + flags.CFlags = append(flags.CFlags, profileSamplingFlag) + flags.LdFlags = append(flags.LdFlags, profileSamplingFlag) } - return "" + return flags } func (pgo *pgo) profileUseFlag(ctx ModuleContext, file string) string { - if *pgo.Properties.Pgo.Instrumentation { + if pgo.Properties.isInstrumentation() { return fmt.Sprintf(profileUseInstrumentFormat, file) } - if *pgo.Properties.Pgo.Sampling { + if pgo.Properties.isSampling() { return fmt.Sprintf(profileUseSamplingFormat, file) } return "" @@ -81,8 +95,8 @@ func (pgo *pgo) profileUseFlags(ctx ModuleContext, file string) []string { } func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { - isInstrumentation := props.Pgo.Instrumentation != nil - isSampling := props.Pgo.Sampling != nil + isInstrumentation := props.isInstrumentation() + isSampling := props.isSampling() profileKindPresent := isInstrumentation || isSampling filePresent := props.Pgo.Profile_file != nil @@ -156,6 +170,14 @@ func (pgo *pgo) begin(ctx BaseModuleContext) { } } +func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps { + if pgo.Properties.ShouldProfileModule { + runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain()) + deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary) + } + return deps +} + func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { if ctx.Host() { return flags @@ -165,10 +187,7 @@ func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { // Add flags to profile this module based on its profile_kind if props.ShouldProfileModule { - profileGatherFlags := pgo.profileGatherFlags(ctx) - flags.LdFlags = append(flags.LdFlags, profileGatherFlags) - flags.CFlags = append(flags.CFlags, profileGatherFlags) - return flags + return pgo.addProfileGatherFlags(ctx, flags) } // If the PGO profiles project is found, and this module has PGO