diff options
Diffstat (limited to 'libc-top-half/musl/tools')
-rw-r--r-- | libc-top-half/musl/tools/add-cfi.common.awk | 26 | ||||
-rw-r--r-- | libc-top-half/musl/tools/add-cfi.i386.awk | 209 | ||||
-rw-r--r-- | libc-top-half/musl/tools/add-cfi.x86_64.awk | 196 | ||||
-rwxr-xr-x | libc-top-half/musl/tools/install.sh | 64 | ||||
-rw-r--r-- | libc-top-half/musl/tools/ld.musl-clang.in | 51 | ||||
-rw-r--r-- | libc-top-half/musl/tools/mkalltypes.sed | 15 | ||||
-rw-r--r-- | libc-top-half/musl/tools/musl-clang.in | 35 | ||||
-rw-r--r-- | libc-top-half/musl/tools/musl-gcc.specs.sh | 37 | ||||
-rw-r--r-- | libc-top-half/musl/tools/version.sh | 12 |
9 files changed, 645 insertions, 0 deletions
diff --git a/libc-top-half/musl/tools/add-cfi.common.awk b/libc-top-half/musl/tools/add-cfi.common.awk new file mode 100644 index 0000000..04482d4 --- /dev/null +++ b/libc-top-half/musl/tools/add-cfi.common.awk @@ -0,0 +1,26 @@ +function hex2int(str, i) { + str = tolower(str) + + for (i = 1; i <= 16; i++) { + char = substr("0123456789abcdef", i, 1) + lookup[char] = i-1 + } + + result = 0 + for (i = 1; i <= length(str); i++) { + result = result * 16 + char = substr(str, i, 1) + result = result + lookup[char] + } + return result +} + +function parse_const(str) { + sign = sub(/^-/, "", str) + hex = sub(/^0x/, "", str) + if (hex) + n = hex2int(str) + else + n = str+0 + return sign ? -n : n +} diff --git a/libc-top-half/musl/tools/add-cfi.i386.awk b/libc-top-half/musl/tools/add-cfi.i386.awk new file mode 100644 index 0000000..d05037d --- /dev/null +++ b/libc-top-half/musl/tools/add-cfi.i386.awk @@ -0,0 +1,209 @@ +# Insert GAS CFI directives ("control frame information") into x86-32 asm input +# +# CFI directives tell the assembler how to generate "stack frame" debug info +# This information can tell a debugger (like gdb) how to find the current stack +# frame at any point in the program code, and how to find the values which +# various registers had at higher points in the call stack +# With this information, the debugger can show a backtrace, and you can move up +# and down the call stack and examine the values of local variables + +BEGIN { + # don't put CFI data in the .eh_frame ELF section (which we don't keep) + print ".cfi_sections .debug_frame" + + # only emit CFI directives inside a function + in_function = 0 + + # emit .loc directives with line numbers from original source + printf ".file 1 \"%s\"\n", ARGV[1] + line_number = 0 + + # used to detect "call label; label:" trick + called = "" +} + +function get_const1() { + # for instructions with 2 operands, get 1st operand (assuming it is constant) + match($0, /-?(0x[0-9a-fA-F]+|[0-9]+),/) + return parse_const(substr($0, RSTART, RLENGTH-1)) +} + +function canonicalize_reg(register) { + if (match(register, /^e/)) + return register + else if (match(register, /[hl]$/)) # AH, AL, BH, BL, etc + return "e" substr(register, 1, 1) "x" + else # AX, BX, CX, etc + return "e" register +} +function get_reg() { + # only use if you already know there is 1 and only 1 register + match($0, /%e?([abcd][hlx]|si|di|bp)/) + return canonicalize_reg(substr($0, RSTART+1, RLENGTH-1)) +} +function get_reg1() { + # for instructions with 2 operands, get 1st operand (assuming it is register) + match($0, /%e?([abcd][hlx]|si|di|bp),/) + return canonicalize_reg(substr($0, RSTART+1, RLENGTH-2)) +} +function get_reg2() { + # for instructions with 2 operands, get 2nd operand (assuming it is register) + match($0, /,%e?([abcd][hlx]|si|di|bp)/) + return canonicalize_reg(substr($0, RSTART+2, RLENGTH-2)) +} + +function adjust_sp_offset(delta) { + if (in_function) + printf ".cfi_adjust_cfa_offset %d\n", delta +} + +{ + line_number = line_number + 1 + + # clean the input up before doing anything else + # delete comments + gsub(/(#|\/\/).*/, "") + + # canonicalize whitespace + gsub(/[ \t]+/, " ") # mawk doesn't understand \s + gsub(/ *, */, ",") + gsub(/ *: */, ": ") + gsub(/ $/, "") + gsub(/^ /, "") +} + +# check for assembler directives which we care about +/^\.(section|data|text)/ { + # a .cfi_startproc/.cfi_endproc pair should be within the same section + # otherwise, clang will choke when generating ELF output + if (in_function) { + print ".cfi_endproc" + in_function = 0 + } +} +/^\.type [a-zA-Z0-9_]+,@function/ { + functions[substr($2, 1, length($2)-10)] = 1 +} +# not interested in assembler directives beyond this, just pass them through +/^\./ { + print + next +} + +/^[a-zA-Z0-9_]+:/ { + label = substr($1, 1, length($1)-1) # drop trailing : + + if (called == label) { + # note adjustment of stack pointer from "call label; label:" + adjust_sp_offset(4) + } + + if (functions[label]) { + if (in_function) + print ".cfi_endproc" + + in_function = 1 + print ".cfi_startproc" + + for (register in saved) + delete saved[register] + for (register in dirty) + delete dirty[register] + } + + # an instruction may follow on the same line, so continue processing +} + +/^$/ { next } + +{ + called = "" + printf ".loc 1 %d\n", line_number + print +} + +# KEEPING UP WITH THE STACK POINTER +# We do NOT attempt to understand foolish and ridiculous tricks like stashing +# the stack pointer and then using %esp as a scratch register, or bitshifting +# it or taking its square root or anything stupid like that. +# %esp should only be adjusted by pushing/popping or adding/subtracting constants +# +/pushl?/ { + if (match($0, / %(ax|bx|cx|dx|di|si|bp|sp)/)) + adjust_sp_offset(2) + else + adjust_sp_offset(4) +} +/popl?/ { + if (match($0, / %(ax|bx|cx|dx|di|si|bp|sp)/)) + adjust_sp_offset(-2) + else + adjust_sp_offset(-4) +} +/addl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%esp/ { adjust_sp_offset(-get_const1()) } +/subl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%esp/ { adjust_sp_offset(get_const1()) } + +/call/ { + if (match($0, /call [0-9]+f/)) # "forward" label + called = substr($0, RSTART+5, RLENGTH-6) + else if (match($0, /call [0-9a-zA-Z_]+/)) + called = substr($0, RSTART+5, RLENGTH-5) +} + +# TRACKING REGISTER VALUES FROM THE PREVIOUS STACK FRAME +# +/pushl? %e(ax|bx|cx|dx|si|di|bp)/ { # don't match "push (%reg)" + # if a register is being pushed, and its value has not changed since the + # beginning of this function, the pushed value can be used when printing + # local variables at the next level up the stack + # emit '.cfi_rel_offset' for that + + if (in_function) { + register = get_reg() + if (!saved[register] && !dirty[register]) { + printf ".cfi_rel_offset %s,0\n", register + saved[register] = 1 + } + } +} + +/movl? %e(ax|bx|cx|dx|si|di|bp),-?(0x[0-9a-fA-F]+|[0-9]+)?\(%esp\)/ { + if (in_function) { + register = get_reg() + if (match($0, /-?(0x[0-9a-fA-F]+|[0-9]+)\(%esp\)/)) { + offset = parse_const(substr($0, RSTART, RLENGTH-6)) + } else { + offset = 0 + } + if (!saved[register] && !dirty[register]) { + printf ".cfi_rel_offset %s,%d\n", register, offset + saved[register] = 1 + } + } +} + +# IF REGISTER VALUES ARE UNCEREMONIOUSLY TRASHED +# ...then we want to know about it. +# +function trashed(register) { + if (in_function && !saved[register] && !dirty[register]) { + printf ".cfi_undefined %s\n", register + } + dirty[register] = 1 +} +# this does NOT exhaustively check for all possible instructions which could +# overwrite a register value inherited from the caller (just the common ones) +/mov.*,%e?([abcd][hlx]|si|di|bp)$/ { trashed(get_reg2()) } +/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%e?([abcd][hlx]|si|di|bp)$/ { + trashed(get_reg2()) +} +/^i?mul [^,]*$/ { trashed("eax"); trashed("edx") } +/^i?mul.*,%e?([abcd][hlx]|si|di|bp)$/ { trashed(get_reg2()) } +/^i?div/ { trashed("eax"); trashed("edx") } +/(dec|inc|not|neg|pop) %e?([abcd][hlx]|si|di|bp)/ { trashed(get_reg()) } +/cpuid/ { trashed("eax"); trashed("ebx"); trashed("ecx"); trashed("edx") } + +END { + if (in_function) + print ".cfi_endproc" +} diff --git a/libc-top-half/musl/tools/add-cfi.x86_64.awk b/libc-top-half/musl/tools/add-cfi.x86_64.awk new file mode 100644 index 0000000..7e1513d --- /dev/null +++ b/libc-top-half/musl/tools/add-cfi.x86_64.awk @@ -0,0 +1,196 @@ +# Insert GAS CFI directives ("control frame information") into x86-64 asm input + +BEGIN { + # don't put CFI data in the .eh_frame ELF section (which we don't keep) + print ".cfi_sections .debug_frame" + + # only emit CFI directives inside a function + in_function = 0 + + # emit .loc directives with line numbers from original source + printf ".file 1 \"%s\"\n", ARGV[1] + line_number = 0 + + # used to detect "call label; label:" trick + called = "" +} + +function get_const1() { + # for instructions with 2 operands, get 1st operand (assuming it is constant) + match($0, /-?(0x[0-9a-fA-F]+|[0-9]+),/) + return parse_const(substr($0, RSTART, RLENGTH-1)) +} + +function canonicalize_reg(register) { + if (match(register, /^r/)) + return register + else if (match(register, /^e/)) + return "r" substr(register, 2, length(register)-1) + else if (match(register, /[hl]$/)) # AH, AL, BH, BL, etc + return "r" substr(register, 1, 1) "x" + else # AX, BX, CX, etc + return "r" register +} +function get_reg() { + # only use if you already know there is 1 and only 1 register + match($0, /%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)/) + return canonicalize_reg(substr($0, RSTART+1, RLENGTH-1)) +} +function get_reg1() { + # for instructions with 2 operands, get 1st operand (assuming it is register) + match($0, /%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15),/) + return canonicalize_reg(substr($0, RSTART+1, RLENGTH-2)) +} +function get_reg2() { + # for instructions with 2 operands, get 2nd operand (assuming it is register) + match($0, /,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)/) + return canonicalize_reg(substr($0, RSTART+2, RLENGTH-2)) +} + +function adjust_sp_offset(delta) { + if (in_function) + printf ".cfi_adjust_cfa_offset %d\n", delta +} + +{ + line_number = line_number + 1 + + # clean the input up before doing anything else + # delete comments + gsub(/(#|\/\/).*/, "") + + # canonicalize whitespace + gsub(/[ \t]+/, " ") # mawk doesn't understand \s + gsub(/ *, */, ",") + gsub(/ *: */, ": ") + gsub(/ $/, "") + gsub(/^ /, "") +} + +# check for assembler directives which we care about +/^\.(section|data|text)/ { + # a .cfi_startproc/.cfi_endproc pair should be within the same section + # otherwise, clang will choke when generating ELF output + if (in_function) { + print ".cfi_endproc" + in_function = 0 + } +} +/^\.type [a-zA-Z0-9_]+,@function/ { + functions[substr($2, 1, length($2)-10)] = 1 +} +# not interested in assembler directives beyond this, just pass them through +/^\./ { + print + next +} + +/^[a-zA-Z0-9_]+:/ { + label = substr($1, 1, length($1)-1) # drop trailing : + + if (called == label) { + # note adjustment of stack pointer from "call label; label:" + adjust_sp_offset(8) + } + + if (functions[label]) { + if (in_function) + print ".cfi_endproc" + + in_function = 1 + print ".cfi_startproc" + + for (register in saved) + delete saved[register] + for (register in dirty) + delete dirty[register] + } + + # an instruction may follow on the same line, so continue processing +} + +/^$/ { next } + +{ + called = "" + printf ".loc 1 %d\n", line_number + print +} + +# KEEPING UP WITH THE STACK POINTER +# %rsp should only be adjusted by pushing/popping or adding/subtracting constants +# +/pushl?/ { + adjust_sp_offset(8) +} +/popl?/ { + adjust_sp_offset(-8) +} +/addl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%rsp/ { adjust_sp_offset(-get_const1()) } +/subl? \$-?(0x[0-9a-fA-F]+|[0-9]+),%rsp/ { adjust_sp_offset(get_const1()) } + +/call/ { + if (match($0, /call [0-9]+f/)) # "forward" label + called = substr($0, RSTART+5, RLENGTH-6) + else if (match($0, /call [0-9a-zA-Z_]+/)) + called = substr($0, RSTART+5, RLENGTH-5) +} + +# TRACKING REGISTER VALUES FROM THE PREVIOUS STACK FRAME +# +/pushl? %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15)/ { # don't match "push (%reg)" + # if a register is being pushed, and its value has not changed since the + # beginning of this function, the pushed value can be used when printing + # local variables at the next level up the stack + # emit '.cfi_rel_offset' for that + + if (in_function) { + register = get_reg() + if (!saved[register] && !dirty[register]) { + printf ".cfi_rel_offset %s,0\n", register + saved[register] = 1 + } + } +} + +/movl? %r(ax|bx|cx|dx|si|di|bp|8|9|10|11|12|13|14|15),-?(0x[0-9a-fA-F]+|[0-9]+)?\(%rsp\)/ { + if (in_function) { + register = get_reg() + if (match($0, /-?(0x[0-9a-fA-F]+|[0-9]+)\(%rsp\)/)) { + offset = parse_const(substr($0, RSTART, RLENGTH-6)) + } else { + offset = 0 + } + if (!saved[register] && !dirty[register]) { + printf ".cfi_rel_offset %s,%d\n", register, offset + saved[register] = 1 + } + } +} + +# IF REGISTER VALUES ARE UNCEREMONIOUSLY TRASHED +# ...then we want to know about it. +# +function trashed(register) { + if (in_function && !saved[register] && !dirty[register]) { + printf ".cfi_undefined %s\n", register + } + dirty[register] = 1 +} +# this does NOT exhaustively check for all possible instructions which could +# overwrite a register value inherited from the caller (just the common ones) +/mov.*,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)$/ { trashed(get_reg2()) } +/(add|addl|sub|subl|and|or|xor|lea|sal|sar|shl|shr).*,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)$/ { + trashed(get_reg2()) +} +/^i?mul [^,]*$/ { trashed("rax"); trashed("rdx") } +/^i?mul.*,%[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)$/ { trashed(get_reg2()) } +/^i?div/ { trashed("rax"); trashed("rdx") } + +/(dec|inc|not|neg|pop) %[er]?([abcd][xlh]|si|di|bp|8|9|10|11|12|13|14|15)/ { trashed(get_reg()) } +/cpuid/ { trashed("rax"); trashed("rbx"); trashed("rcx"); trashed("rdx") } + +END { + if (in_function) + print ".cfi_endproc" +} diff --git a/libc-top-half/musl/tools/install.sh b/libc-top-half/musl/tools/install.sh new file mode 100755 index 0000000..d913b60 --- /dev/null +++ b/libc-top-half/musl/tools/install.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# +# This is an actually-safe install command which installs the new +# file atomically in the new location, rather than overwriting +# existing files. +# + +usage() { +printf "usage: %s [-D] [-l] [-m mode] src dest\n" "$0" 1>&2 +exit 1 +} + +mkdirp= +symlink= +mode=755 + +while getopts Dlm: name ; do +case "$name" in +D) mkdirp=yes ;; +l) symlink=yes ;; +m) mode=$OPTARG ;; +?) usage ;; +esac +done +shift $(($OPTIND - 1)) + +test "$#" -eq 2 || usage +src=$1 +dst=$2 +tmp="$dst.tmp.$$" + +case "$dst" in +*/) printf "%s: %s ends in /\n", "$0" "$dst" 1>&2 ; exit 1 ;; +esac + +set -C +set -e + +if test "$mkdirp" ; then +umask 022 +case "$2" in +*/*) mkdir -p "${dst%/*}" ;; +esac +fi + +trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP + +umask 077 + +if test "$symlink" ; then +ln -s "$1" "$tmp" +else +cat < "$1" > "$tmp" +chmod "$mode" "$tmp" +fi + +mv -f "$tmp" "$2" +test -d "$2" && { +rm -f "$2/$tmp" +printf "%s: %s is a directory\n" "$0" "$dst" 1>&2 +exit 1 +} + +exit 0 diff --git a/libc-top-half/musl/tools/ld.musl-clang.in b/libc-top-half/musl/tools/ld.musl-clang.in new file mode 100644 index 0000000..93763d6 --- /dev/null +++ b/libc-top-half/musl/tools/ld.musl-clang.in @@ -0,0 +1,51 @@ +#!/bin/sh +cc="@CC@" +libc_lib="@LIBDIR@" +ldso="@LDSO@" +cleared= +shared= +userlinkdir= +userlink= + +for x ; do + test "$cleared" || set -- ; cleared=1 + + case "$x" in + -L-user-start) + userlinkdir=1 + ;; + -L-user-end) + userlinkdir= + ;; + -L*) + test "$userlinkdir" && set -- "$@" "$x" + ;; + -l-user-start) + userlink=1 + ;; + -l-user-end) + userlink= + ;; + crtbegin*.o|crtend*.o) + set -- "$@" $($cc -print-file-name=$x) + ;; + -lgcc|-lgcc_eh) + file=lib${x#-l}.a + set -- "$@" $($cc -print-file-name=$file) + ;; + -l*) + test "$userlink" && set -- "$@" "$x" + ;; + -shared) + shared=1 + set -- "$@" -shared + ;; + -sysroot=*|--sysroot=*) + ;; + *) + set -- "$@" "$x" + ;; + esac +done + +exec $($cc -print-prog-name=ld) -nostdlib "$@" -lc -dynamic-linker "$ldso" diff --git a/libc-top-half/musl/tools/mkalltypes.sed b/libc-top-half/musl/tools/mkalltypes.sed new file mode 100644 index 0000000..fa15efc --- /dev/null +++ b/libc-top-half/musl/tools/mkalltypes.sed @@ -0,0 +1,15 @@ +/^TYPEDEF/s/TYPEDEF \(.*\) \([^ ]*\);$/#if defined(__NEED_\2) \&\& !defined(__DEFINED_\2)\ +typedef \1 \2;\ +#define __DEFINED_\2\ +#endif\ +/ +/^STRUCT/s/STRUCT * \([^ ]*\) \(.*\);$/#if defined(__NEED_struct_\1) \&\& !defined(__DEFINED_struct_\1)\ +struct \1 \2;\ +#define __DEFINED_struct_\1\ +#endif\ +/ +/^UNION/s/UNION * \([^ ]*\) \(.*\);$/#if defined(__NEED_union_\1) \&\& !defined(__DEFINED_union_\1)\ +union \1 \2;\ +#define __DEFINED_union_\1\ +#endif\ +/ diff --git a/libc-top-half/musl/tools/musl-clang.in b/libc-top-half/musl/tools/musl-clang.in new file mode 100644 index 0000000..623de6f --- /dev/null +++ b/libc-top-half/musl/tools/musl-clang.in @@ -0,0 +1,35 @@ +#!/bin/sh +cc="@CC@" +libc="@PREFIX@" +libc_inc="@INCDIR@" +libc_lib="@LIBDIR@" +thisdir="`cd "$(dirname "$0")"; pwd`" + +# prevent clang from running the linker (and erroring) on no input. +sflags= +eflags= +for x ; do + case "$x" in + -l*) input=1 ;; + *) input= ;; + esac + if test "$input" ; then + sflags="-l-user-start" + eflags="-l-user-end" + break + fi +done + +exec $cc \ + -B"$thisdir" \ + -fuse-ld=musl-clang \ + -static-libgcc \ + -nostdinc \ + --sysroot "$libc" \ + -isystem "$libc_inc" \ + -L-user-start \ + $sflags \ + "$@" \ + $eflags \ + -L"$libc_lib" \ + -L-user-end diff --git a/libc-top-half/musl/tools/musl-gcc.specs.sh b/libc-top-half/musl/tools/musl-gcc.specs.sh new file mode 100644 index 0000000..3049257 --- /dev/null +++ b/libc-top-half/musl/tools/musl-gcc.specs.sh @@ -0,0 +1,37 @@ +incdir=$1 +libdir=$2 +ldso=$3 +cat <<EOF +%rename cpp_options old_cpp_options + +*cpp_options: +-nostdinc -isystem $incdir -isystem include%s %(old_cpp_options) + +*cc1: +%(cc1_cpu) -nostdinc -isystem $incdir -isystem include%s + +*link_libgcc: +-L$libdir -L .%s + +*libgcc: +libgcc.a%s %:if-exists(libgcc_eh.a%s) + +*startfile: +%{!shared: $libdir/Scrt1.o} $libdir/crti.o crtbeginS.o%s + +*endfile: +crtendS.o%s $libdir/crtn.o + +*link: +-dynamic-linker $ldso -nostdlib %{shared:-shared} %{static:-static} %{rdynamic:-export-dynamic} + +*esp_link: + + +*esp_options: + + +*esp_cpp_options: + + +EOF diff --git a/libc-top-half/musl/tools/version.sh b/libc-top-half/musl/tools/version.sh new file mode 100644 index 0000000..f1cc594 --- /dev/null +++ b/libc-top-half/musl/tools/version.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if test -d .git ; then +if type git >/dev/null 2>&1 ; then +git describe --tags --match 'v[0-9]*' 2>/dev/null \ +| sed -e 's/^v//' -e 's/-/-git-/' +else +sed 's/$/-git/' < VERSION +fi +else +cat VERSION +fi |