[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:
Roland McGrath
2017-07-18 20:28:30 -07:00
commit a966ef0c44
6 arquivos alterados com 82 adições e 25 exclusões
+2 -1
Ver Arquivo
@@ -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)
+2 -1
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
+67 -7
Ver Arquivo
@@ -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
Ver Arquivo
@@ -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
}
+8 -7
Ver Arquivo
@@ -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)