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 <pirama@google.com>
This commit is contained in:
Pirama Arumuga Nainar
2017-10-04 16:47:29 -07:00
parent 60e38b613f
commit 49b53d5c7c
3 changed files with 43 additions and 14 deletions

View File

@@ -673,6 +673,12 @@ func (c *Module) deps(ctx DepsContext) Deps {
if c.compiler != nil { if c.compiler != nil {
deps = c.compiler.compilerDeps(ctx, deps) 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 { if c.linker != nil {
deps = c.linker.linkerDeps(ctx, deps) deps = c.linker.linkerDeps(ctx, deps)
} }

View File

@@ -233,6 +233,10 @@ func ThreadSanitizerRuntimeLibrary(t Toolchain) string {
return SanitizerRuntimeLibrary(t, "tsan") return SanitizerRuntimeLibrary(t, "tsan")
} }
func ProfileRuntimeLibrary(t Toolchain) string {
return SanitizerRuntimeLibrary(t, "profile")
}
func ToolPath(t Toolchain) string { func ToolPath(t Toolchain) string {
if p := t.ToolPath(); p != "" { if p := t.ToolPath(); p != "" {
return p return p

View File

@@ -19,6 +19,7 @@ import (
"strings" "strings"
"android/soong/android" "android/soong/android"
"android/soong/cc/config"
) )
var ( var (
@@ -50,25 +51,38 @@ type pgo struct {
Properties PgoProperties 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{} { func (pgo *pgo) props() []interface{} {
return []interface{}{&pgo.Properties} return []interface{}{&pgo.Properties}
} }
func (pgo *pgo) profileGatherFlags(ctx ModuleContext) string { func (pgo *pgo) addProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
if *pgo.Properties.Pgo.Instrumentation { if pgo.Properties.isInstrumentation() {
return profileInstrumentFlag 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 { if pgo.Properties.isSampling() {
return profileSamplingFlag flags.CFlags = append(flags.CFlags, profileSamplingFlag)
flags.LdFlags = append(flags.LdFlags, profileSamplingFlag)
} }
return "" return flags
} }
func (pgo *pgo) profileUseFlag(ctx ModuleContext, file string) string { func (pgo *pgo) profileUseFlag(ctx ModuleContext, file string) string {
if *pgo.Properties.Pgo.Instrumentation { if pgo.Properties.isInstrumentation() {
return fmt.Sprintf(profileUseInstrumentFormat, file) return fmt.Sprintf(profileUseInstrumentFormat, file)
} }
if *pgo.Properties.Pgo.Sampling { if pgo.Properties.isSampling() {
return fmt.Sprintf(profileUseSamplingFormat, file) return fmt.Sprintf(profileUseSamplingFormat, file)
} }
return "" return ""
@@ -81,8 +95,8 @@ func (pgo *pgo) profileUseFlags(ctx ModuleContext, file string) []string {
} }
func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
isInstrumentation := props.Pgo.Instrumentation != nil isInstrumentation := props.isInstrumentation()
isSampling := props.Pgo.Sampling != nil isSampling := props.isSampling()
profileKindPresent := isInstrumentation || isSampling profileKindPresent := isInstrumentation || isSampling
filePresent := props.Pgo.Profile_file != nil 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 { func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
if ctx.Host() { if ctx.Host() {
return flags 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 // Add flags to profile this module based on its profile_kind
if props.ShouldProfileModule { if props.ShouldProfileModule {
profileGatherFlags := pgo.profileGatherFlags(ctx) return pgo.addProfileGatherFlags(ctx, flags)
flags.LdFlags = append(flags.LdFlags, profileGatherFlags)
flags.CFlags = append(flags.CFlags, profileGatherFlags)
return flags
} }
// If the PGO profiles project is found, and this module has PGO // If the PGO profiles project is found, and this module has PGO