diff options
author | Dan Willemsen <dwillemsen@google.com> | 2018-10-12 00:24:23 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@google.com> | 2018-10-22 15:46:03 -0700 |
commit | a0790e35c7b275ee3b8288cf5453c15390850458 (patch) | |
tree | 1952cc9a1d0229ab60a8c0e36e593f3716113c5a /cmd/host_bionic_inject | |
parent | 9ff34c0ca8bc4f8b26424c58978b89eb25fd1564 (diff) | |
download | soong-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.bp | 19 | ||||
-rw-r--r-- | cmd/host_bionic_inject/host_bionic_inject.go | 174 |
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 +} |