aboutsummaryrefslogtreecommitdiff
path: root/cmd/host_bionic_inject
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2018-10-12 00:24:23 -0700
committerDan Willemsen <dwillemsen@google.com>2018-10-22 15:46:03 -0700
commita0790e35c7b275ee3b8288cf5453c15390850458 (patch)
tree1952cc9a1d0229ab60a8c0e36e593f3716113c5a /cmd/host_bionic_inject
parent9ff34c0ca8bc4f8b26424c58978b89eb25fd1564 (diff)
downloadsoong-a0790e35c7b275ee3b8288cf5453c15390850458.tar.gz
Rework how linux_bionic is built with LLD
In order to simplify the wrapper function, and stop using a linker script, generate a set of flags to pass to LLD. Then run host_bionic_inject on the linked binary in order to verify the embedding, and give the wrapper function the address of the original entry point (_start). Bug: 31559095 Test: build host bionic with prebuilts/build-tools/build-prebuilts.sh Change-Id: I53e326050e0f9caa562c6cf6f76c4d0337bb6faf
Diffstat (limited to 'cmd/host_bionic_inject')
-rw-r--r--cmd/host_bionic_inject/Android.bp19
-rw-r--r--cmd/host_bionic_inject/host_bionic_inject.go174
2 files changed, 193 insertions, 0 deletions
diff --git a/cmd/host_bionic_inject/Android.bp b/cmd/host_bionic_inject/Android.bp
new file mode 100644
index 000000000..acce68386
--- /dev/null
+++ b/cmd/host_bionic_inject/Android.bp
@@ -0,0 +1,19 @@
+// 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.
+
+blueprint_go_binary {
+ name: "host_bionic_inject",
+ deps: ["soong-symbol_inject"],
+ srcs: ["host_bionic_inject.go"],
+}
diff --git a/cmd/host_bionic_inject/host_bionic_inject.go b/cmd/host_bionic_inject/host_bionic_inject.go
new file mode 100644
index 000000000..0dabbba2d
--- /dev/null
+++ b/cmd/host_bionic_inject/host_bionic_inject.go
@@ -0,0 +1,174 @@
+// 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.
+
+// Verifies a host bionic executable with an embedded linker, then injects
+// the address of the _start function for the linker_wrapper to use.
+package main
+
+import (
+ "debug/elf"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+
+ "android/soong/symbol_inject"
+)
+
+func main() {
+ var inputFile, linkerFile, outputFile string
+
+ flag.StringVar(&inputFile, "i", "", "Input file")
+ flag.StringVar(&linkerFile, "l", "", "Linker file")
+ flag.StringVar(&outputFile, "o", "", "Output file")
+ flag.Parse()
+
+ if inputFile == "" || linkerFile == "" || outputFile == "" || flag.NArg() != 0 {
+ flag.Usage()
+ os.Exit(1)
+ }
+
+ r, err := os.Open(inputFile)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(2)
+ }
+ defer r.Close()
+
+ file, err := symbol_inject.OpenFile(r)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(3)
+ }
+
+ linker, err := elf.Open(linkerFile)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(4)
+ }
+
+ start_addr, err := parseElf(r, linker)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(5)
+ }
+
+ w, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(6)
+ }
+ defer w.Close()
+
+ err = symbol_inject.InjectUint64Symbol(file, w, "__dlwrap_original_start", start_addr)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(7)
+ }
+}
+
+// Check the ELF file, and return the address to the _start function
+func parseElf(r io.ReaderAt, linker *elf.File) (uint64, error) {
+ file, err := elf.NewFile(r)
+ if err != nil {
+ return 0, err
+ }
+
+ symbols, err := file.Symbols()
+ if err != nil {
+ return 0, err
+ }
+
+ for _, prog := range file.Progs {
+ if prog.Type == elf.PT_INTERP {
+ return 0, fmt.Errorf("File should not have a PT_INTERP header")
+ }
+ }
+
+ if dlwrap_start, err := findSymbol(symbols, "__dlwrap__start"); err != nil {
+ return 0, err
+ } else if dlwrap_start.Value != file.Entry {
+ return 0, fmt.Errorf("Expected file entry(0x%x) to point to __dlwrap_start(0x%x)",
+ file.Entry, dlwrap_start.Value)
+ }
+
+ err = checkLinker(file, linker, symbols)
+ if err != nil {
+ return 0, err
+ }
+
+ start, err := findSymbol(symbols, "_start")
+ if err != nil {
+ return 0, fmt.Errorf("Failed to find _start symbol")
+ }
+ return start.Value, nil
+}
+
+func findSymbol(symbols []elf.Symbol, name string) (elf.Symbol, error) {
+ for _, sym := range symbols {
+ if sym.Name == name {
+ return sym, nil
+ }
+ }
+ return elf.Symbol{}, fmt.Errorf("Failed to find symbol %q", name)
+}
+
+// Check that all of the PT_LOAD segments have been embedded properly
+func checkLinker(file, linker *elf.File, fileSyms []elf.Symbol) error {
+ dlwrap_linker_offset, err := findSymbol(fileSyms, "__dlwrap_linker_offset")
+ if err != nil {
+ return err
+ }
+
+ for i, lprog := range linker.Progs {
+ if lprog.Type != elf.PT_LOAD {
+ continue
+ }
+
+ found := false
+ for j, prog := range file.Progs {
+ if prog.Type != elf.PT_LOAD {
+ continue
+ }
+
+ if lprog.Vaddr+dlwrap_linker_offset.Value != prog.Vaddr {
+ continue
+ }
+ found = true
+
+ if lprog.Memsz != prog.Memsz {
+ return fmt.Errorf("Linker prog %d (0x%x) memsz (0x%x) does not match (0x%x)",
+ i, lprog.Vaddr, lprog.Memsz, prog.Memsz)
+ }
+
+ // The linker shouldn't be using BSS, since only one
+ // BSS section is supported per ELF file.
+ if prog.Memsz != prog.Filesz {
+ return fmt.Errorf("Embedded prog %d (0x%x) memsz (0x%x) does not match filesz (0x%x)",
+ j, prog.Vaddr, prog.Memsz, prog.Filesz)
+ }
+
+ if lprog.Flags != prog.Flags {
+ return fmt.Errorf("Linker prog %d (0x%x) flags (%s) do not match (%s)",
+ i, lprog.Vaddr, lprog.Flags, prog.Flags)
+ }
+ }
+ if !found {
+ return fmt.Errorf("Linker prog %d (0x%x) not found at offset 0x%x",
+ i, lprog.Vaddr, dlwrap_linker_offset.Value)
+ }
+ }
+
+ return nil
+}