[build] Don't define special symbols in rodso.ld
This changes rodso.ld so its only effect is to produce the
desired optimal layout. It no longer defines special symbols for
use by scripts/gen-rodso-code.sh. (The rodso.ld layout is now what
will become the default for lld with -z rodynamic for these cases
once some corner case issues are resolved in lld.)
Instead, scripts/gen-rodso-code.sh is slightly reworked to glean
the values for the CODE_{START,END} and DATA_{START,END}_dynsym
constants from ELF program and section headers rather than from
symbol values defined by the linker script. userboot's generated
linker script for vDSO access uses linker-script arithmetic to
align the value from the linker's built-in _end symbol rather
than relying on a CODE_END symbol being defined by rodso.ld.
Change-Id: I200b687824c36ec3bd9e7d9d2a25464727ba09ee
Esse commit está contido em:
@@ -26,7 +26,8 @@ MODULE_SRCDEPS += $(BUILDDIR)/$(LOCAL_DIR)/userboot-code.h
|
||||
$(BUILDDIR)/$(LOCAL_DIR)/userboot-code.h: scripts/gen-rodso-code.sh $(userboot-filename)
|
||||
@$(MKDIR)
|
||||
$(call BUILDECHO,generating $@)
|
||||
$(NOECHO)$(SHELLEXEC) $< '$(NM)' $@.new USERBOOT $(userboot-filename)
|
||||
$(NOECHO)$(SHELLEXEC) $< '$(NM)' '$(READELF)' \
|
||||
$@.new USERBOOT $(userboot-filename)
|
||||
@mv -f $@.new $@
|
||||
GENERATED += $(BUILDDIR)/$(LOCAL_DIR)/userboot-code.h
|
||||
MODULE_COMPILEFLAGS += -I$(BUILDDIR)/$(LOCAL_DIR)
|
||||
|
||||
@@ -27,7 +27,8 @@ MODULE_SRCDEPS += $(BUILDDIR)/$(LOCAL_DIR)/vdso-code.h
|
||||
$(BUILDDIR)/$(LOCAL_DIR)/vdso-code.h: scripts/gen-rodso-code.sh $(vdso-filename)
|
||||
@$(MKDIR)
|
||||
$(call BUILDECHO,generating $@)
|
||||
$(NOECHO)$(SHELLEXEC) $< '$(NM)' $@.new VDSO $(vdso-filename)
|
||||
$(NOECHO)$(SHELLEXEC) $< '$(NM)' '$(READELF)' \
|
||||
$@.new VDSO $(vdso-filename)
|
||||
@mv -f $@.new $@
|
||||
GENERATED += $(BUILDDIR)/$(LOCAL_DIR)/vdso-code.h
|
||||
MODULE_COMPILEFLAGS += -I$(BUILDDIR)/$(LOCAL_DIR)
|
||||
|
||||
+2
-2
@@ -535,7 +535,7 @@ ifeq ($(call TOBOOL,$(USE_CLANG)),true)
|
||||
CC := $(CLANG_TOOLCHAIN_PREFIX)clang
|
||||
AR := $(CLANG_TOOLCHAIN_PREFIX)llvm-ar
|
||||
OBJDUMP := $(CLANG_TOOLCHAIN_PREFIX)llvm-objdump
|
||||
READELF := $(CLANG_TOOLCHAIN_PREFIX)llvm-readobj -elf-output-style=GNU
|
||||
READELF := $(CLANG_TOOLCHAIN_PREFIX)llvm-readelf
|
||||
CPPFILT := $(CLANG_TOOLCHAIN_PREFIX)llvm-cxxfilt
|
||||
SIZE := $(CLANG_TOOLCHAIN_PREFIX)llvm-size
|
||||
NM := $(CLANG_TOOLCHAIN_PREFIX)llvm-nm
|
||||
@@ -597,7 +597,7 @@ HOST_CC := $(HOST_TOOLCHAIN_PREFIX)clang
|
||||
HOST_CXX := $(HOST_TOOLCHAIN_PREFIX)clang++
|
||||
HOST_AR := $(HOST_TOOLCHAIN_PREFIX)llvm-ar
|
||||
HOST_OBJDUMP := $(HOST_TOOLCHAIN_PREFIX)llvm-objdump
|
||||
HOST_READELF := $(HOST_TOOLCHAIN_PREFIX)llvm-readobj
|
||||
HOST_READELF := $(HOST_TOOLCHAIN_PREFIX)llvm-readelf
|
||||
HOST_CPPFILT := $(HOST_TOOLCHAIN_PREFIX)llvm-cxxfilt
|
||||
HOST_SIZE := $(HOST_TOOLCHAIN_PREFIX)llvm-size
|
||||
HOST_NM := $(HOST_TOOLCHAIN_PREFIX)llvm-nm
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# of entries in the table.
|
||||
|
||||
usage() {
|
||||
echo >&2 "Usage: $0 NM OUTFILE {NAME DSO}..."
|
||||
echo >&2 "Usage: $0 NM READELF OUTFILE {NAME DSO}..."
|
||||
exit 2
|
||||
}
|
||||
|
||||
@@ -27,14 +27,14 @@ fi
|
||||
|
||||
NM="$1"
|
||||
shift
|
||||
READELF="$1"
|
||||
shift
|
||||
OUTFILE="$1"
|
||||
shift
|
||||
|
||||
if [ "$(basename $0)" = "sh" ]
|
||||
then
|
||||
set -e
|
||||
else
|
||||
set -o pipefail -e
|
||||
set -e
|
||||
if [ -n "$BASH_VERSION" ]; then
|
||||
set -o pipefail
|
||||
fi
|
||||
|
||||
grok_code_symbols() {
|
||||
@@ -78,12 +78,72 @@ find_dynsym_slots() {
|
||||
"$NM" -P -D -p "$2" | grok_dynsym_slots "$1"
|
||||
}
|
||||
|
||||
SEGMENTS_HAVE_DYNSYM=22
|
||||
SEGMENTS_NO_DYNSYM=33
|
||||
|
||||
grok_segments() {
|
||||
local line
|
||||
local status=$SEGMENTS_NO_DYNSYM
|
||||
while read line; do
|
||||
case "$line" in
|
||||
# Program header for the code segment, e.g.:
|
||||
# LOAD 0x002000 0x0000000000002000 0x0000000000002000 0x00f50f 0x00f50f R E 0x1000
|
||||
# ^^^^^ vaddr ^^^^^^ ^filesz^
|
||||
*LOAD*\ R\ E\ *)
|
||||
local words=($line)
|
||||
local vaddr=$(printf '%#x' ${words[2]})
|
||||
local filesz=$(printf '%#x' ${words[4]})
|
||||
echo "#define ${1}_CODE_START $vaddr" >> $OUTFILE
|
||||
echo "#define ${1}_CODE_END (((${1}_CODE_START + $filesz + (1 << PAGE_SIZE_SHIFT) - 1) >> PAGE_SIZE_SHIFT) << PAGE_SIZE_SHIFT)" >> $OUTFILE
|
||||
;;
|
||||
# Make sure there's no writable segment.
|
||||
*LOAD*W*)
|
||||
echo >&2 "$0: writable segment: $line"
|
||||
exit 1
|
||||
;;
|
||||
# Section header for .dynsym, e.g.:
|
||||
# [ 3] .dynsym DYNSYM 0000000000001268 001268 000018 18 A 6 1 8
|
||||
# ^^^^^ addr ^^^^^ ^size^ ^entsize^
|
||||
*DYNSYM*)
|
||||
line="${line#*DYNSYM}"
|
||||
local words=($line)
|
||||
local addr=$(printf '%#x' 0x${words[0]})
|
||||
local size=$(printf '%#x' 0x${words[2]})
|
||||
local entsize=$(printf '%#x' 0x${words[3]})
|
||||
# A dummy .dynsym has a single entry. Don't count that case.
|
||||
if [ $size != $entsize ]; then
|
||||
status=$SEGMENTS_HAVE_DYNSYM
|
||||
echo "#define ${1}_DATA_START_dynsym $addr" >> $OUTFILE
|
||||
echo "#define ${1}_DATA_END_dynsym (${1}_DATA_START_dynsym + $size)" >> $OUTFILE
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
return $status
|
||||
}
|
||||
|
||||
find_segments() {
|
||||
# This if silliness disarms -e so we can observe grok_segments's return code.
|
||||
if {
|
||||
"$READELF" -W -S -l "$2" | grok_segments "$1"
|
||||
case $? in
|
||||
$SEGMENTS_NO_DYNSYM) have_dynsym=no ;;
|
||||
$SEGMENTS_HAVE_DYNSYM) have_dynsym=yes ;;
|
||||
*) exit $? ;;
|
||||
esac
|
||||
return 0
|
||||
}; then : ; fi
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
if [ $# -lt 2 ]; then
|
||||
usage
|
||||
fi
|
||||
echo "#define ${1}_FILENAME \"${2}\"" > $OUTFILE
|
||||
find_segments "$1" "$2"
|
||||
find_code_symbols "$1" "$2"
|
||||
find_dynsym_slots "$1" "$2"
|
||||
if [ $have_dynsym = yes ]; then
|
||||
find_dynsym_slots "$1" "$2"
|
||||
fi
|
||||
shift 2
|
||||
done
|
||||
|
||||
+1
-7
@@ -62,11 +62,7 @@ SECTIONS {
|
||||
*(.hash)
|
||||
} :rodata
|
||||
.gnu.hash : { *(.gnu.hash) }
|
||||
.dynsym : {
|
||||
HIDDEN(DATA_START_dynsym = .);
|
||||
*(.dynsym)
|
||||
HIDDEN(DATA_END_dynsym = .);
|
||||
}
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
|
||||
.rodata : {
|
||||
@@ -108,7 +104,6 @@ SECTIONS {
|
||||
"rodso code must avoid writable data sections!")
|
||||
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
HIDDEN(CODE_START = .);
|
||||
|
||||
.text : {
|
||||
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||
@@ -129,7 +124,6 @@ SECTIONS {
|
||||
* (.shstrtab, section headers, .symtab if not stripped, etc.).
|
||||
*/
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
HIDDEN(CODE_END = .);
|
||||
} :code
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
|
||||
// For each function in the vDSO ABI, define a symbol in the linker script
|
||||
// pointing to its address. The vDSO is loaded immediately after the
|
||||
// userboot DSO image's last page, which is marked by the CODE_END symbol.
|
||||
// So these symbols tell the linker where each vDSO function will be found
|
||||
// at runtime. The userboot code uses normal calls to these, declared as
|
||||
// have hidden visibility so they won't generate PLT entries. This results
|
||||
// in the userboot binary having simple PC-relative calls to addresses
|
||||
// outside its own image, to where the vDSO will be found at runtime.
|
||||
// userboot DSO image's last page, which is found by aligning the magic
|
||||
// symbol _end (generated by the linker) up to the next page boundary. So
|
||||
// these symbols tell the linker where each vDSO function will be found at
|
||||
// runtime. The userboot code uses normal calls to these, declared as have
|
||||
// hidden visibility so they won't generate PLT entries. This results in
|
||||
// the userboot binary having simple PC-relative calls to addresses outside
|
||||
// its own image, to where the vDSO will be found at runtime.
|
||||
#define FUNCTION(name, address, size) \
|
||||
PROVIDE_HIDDEN(name = CODE_END + address);
|
||||
PROVIDE_HIDDEN(name = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + address);
|
||||
|
||||
#define WEAK_FUNCTION(name, address, size) FUNCTION(name, address, size)
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário