Add support for AArch64 XOM binaries.

Adds build system support for generating AArch64 binaries with
execute-only memory layouts via a new xom module property. Also adds
support for an ENABLE_XOM build flag for global builds.

Bug: 77958880
Test: make -j ENABLE_XOM=true
Change-Id: Ia2ea981498dd12941aaf5ca807648ae37527e3ee
diff --git a/Android.bp b/Android.bp
index ef42c84..be9cf2a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,6 +145,7 @@
         "cc/util.go",
         "cc/vndk.go",
         "cc/vndk_prebuilt.go",
+        "cc/xom.go",
 
         "cc/cmakelists.go",
         "cc/compdb.go",
diff --git a/android/config.go b/android/config.go
index 50c1413..0171cc0 100644
--- a/android/config.go
+++ b/android/config.go
@@ -626,6 +626,14 @@
 	}
 }
 
+func (c *config) EnableXOM() bool {
+	if c.productVariables.EnableXOM == nil {
+		return false
+	} else {
+		return Bool(c.productVariables.EnableXOM)
+	}
+}
+
 func (c *config) Android64() bool {
 	for _, t := range c.Targets[Android] {
 		if t.Arch.ArchType.Multilib == "lib64" {
@@ -863,6 +871,13 @@
 	return PrefixInList(path, *c.productVariables.CFIIncludePaths)
 }
 
+func (c *config) XOMDisabledForPath(path string) bool {
+	if c.productVariables.XOMExcludePaths == nil {
+		return false
+	}
+	return PrefixInList(path, *c.productVariables.XOMExcludePaths)
+}
+
 func (c *config) VendorConfig(name string) VendorConfig {
 	return vendorConfig(c.productVariables.VendorVars[name])
 }
diff --git a/android/variable.go b/android/variable.go
index fbbde36..0b344f9 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -211,6 +211,9 @@
 	CFIExcludePaths *[]string `json:",omitempty"`
 	CFIIncludePaths *[]string `json:",omitempty"`
 
+	EnableXOM       *bool     `json:",omitempty"`
+	XOMExcludePaths *[]string `json:",omitempty"`
+
 	VendorPath          *string `json:",omitempty"`
 	OdmPath             *string `json:",omitempty"`
 	ProductPath         *string `json:",omitempty"`
diff --git a/cc/cc.go b/cc/cc.go
index 5485ae3..3aaaf39 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -360,6 +360,7 @@
 	vndkdep   *vndkdep
 	lto       *lto
 	pgo       *pgo
+	xom       *xom
 
 	androidMkSharedLibDeps []string
 
@@ -417,6 +418,9 @@
 	if c.pgo != nil {
 		c.AddProperties(c.pgo.props()...)
 	}
+	if c.xom != nil {
+		c.AddProperties(c.xom.props()...)
+	}
 	for _, feature := range c.features {
 		c.AddProperties(feature.props()...)
 	}
@@ -658,6 +662,7 @@
 	module.vndkdep = &vndkdep{}
 	module.lto = &lto{}
 	module.pgo = &pgo{}
+	module.xom = &xom{}
 	return module
 }
 
@@ -774,6 +779,9 @@
 	if c.pgo != nil {
 		flags = c.pgo.flags(ctx, flags)
 	}
+	if c.xom != nil {
+		flags = c.xom.flags(ctx, flags)
+	}
 	for _, feature := range c.features {
 		flags = feature.flags(ctx, flags)
 	}
@@ -1641,6 +1649,7 @@
 		&VndkProperties{},
 		&LTOProperties{},
 		&PgoProperties{},
+		&XomProperties{},
 		&android.ProtoProperties{},
 	)
 
diff --git a/cc/xom.go b/cc/xom.go
new file mode 100644
index 0000000..f65fc24
--- /dev/null
+++ b/cc/xom.go
@@ -0,0 +1,75 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+)
+
+type XomProperties struct {
+	Xom *bool
+}
+
+type xom struct {
+	Properties XomProperties
+}
+
+func (xom *xom) props() []interface{} {
+	return []interface{}{&xom.Properties}
+}
+
+func (xom *xom) begin(ctx BaseModuleContext) {}
+
+func (xom *xom) deps(ctx BaseModuleContext, deps Deps) Deps {
+	return deps
+}
+
+func (xom *xom) flags(ctx ModuleContext, flags Flags) Flags {
+	disableXom := false
+
+	if !ctx.Config().EnableXOM() || ctx.Config().XOMDisabledForPath(ctx.ModuleDir()) {
+		disableXom = true
+	}
+
+	if xom.Properties.Xom != nil && !*xom.Properties.Xom {
+		return flags
+	}
+
+	// If any static dependencies have XOM disabled, we should disable XOM in this module,
+	// the assumption being if it's been explicitly disabled then there's probably incompatible
+	// code in the library which may get pulled in.
+	if !ctx.static() && !disableXom {
+		ctx.VisitDirectDeps(func(m android.Module) {
+			cc, ok := m.(*Module)
+			if !ok || cc.xom == nil || !cc.static() {
+				return
+			}
+			if cc.xom.Properties.Xom != nil && !*cc.xom.Properties.Xom {
+				disableXom = true
+				return
+			}
+		})
+	}
+
+	// Enable execute-only if none of the dependencies disable it,
+	// also if it's explicitly set true (allows overriding dependencies disabling it).
+	if !disableXom || (xom.Properties.Xom != nil && *xom.Properties.Xom) {
+		if ctx.Arch().ArchType == android.Arm64 {
+			flags.LdFlags = append(flags.LdFlags, "-Wl,-execute-only")
+		}
+	}
+
+	return flags
+}