Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 208 lines (173 sloc) 5.722 kB
#!/bin/sh
# -----------------------------------------------------------------------
# gentramp.sh - Copyright (c) 2010-2011, Plausible Labs Cooperative, Inc.
#
# Trampoline Page Generator
# Author: Landon Fuller <landonf@plausible.coop>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# ``Software''), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
# -----------------------------------------------------------------------
PROGNAME=$0
INPUT_FILE_PATH="$1"
INPUT_FILE_BASE="`basename -a $(sed s/\.[^.]*$// <<< $INPUT_FILE_PATH)`"
CURRENT_ARCH="$2"
OUTPUT_DIR="$3"
SRC_C_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}_config.c"
SRC_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}.s"
HEADER_OUTPUT="${OUTPUT_DIR}/${INPUT_FILE_BASE}.h"
# Default implementation
trampoline_prefix () {
return 0
}
# Import the trampoline definition
. ${INPUT_FILE_PATH}
check_required () {
local name=$1
eval "local var=\${$1}"
if [ -z "${var}" ]; then
echo "Required variable ${name} not defined."
exit 1
fi
}
check_required ARCH
check_required PAGE_SIZE
check_required PAGE_NAME
# Write a header line
header () {
echo "$1" >> "${HEADER_OUTPUT}"
}
# Write a C source line
src () {
echo "$1" >> "${SRC_C_OUTPUT}"
}
# Flush the assembler output buffer to disk
ASM_BUFFER=""
asm_flush () {
echo "${ASM_BUFFER}" >> "${SRC_OUTPUT}"
asm_discard
}
# Write the assembler buffer to disk, but don't discard the contents
asm_write () {
echo "${ASM_BUFFER}" >> "${SRC_OUTPUT}"
}
# Discard the current assembler output buffer
asm_discard () {
ASM_BUFFER=''
return 0;
}
# Append data to the assembler output buffer
asm () {
local line=""
while read -r line; do
ASM_BUFFER+=$line
ASM_BUFFER+="\n"
done
}
# Compute the assembled size of the current assembler buffer
compute_asm_size () {
# Create the temporary assembler file
local output=".globl _byte_count_start\n"
output+="_byte_count_start:\n"
output+="${ASM_BUFFER}"
output+=".globl _byte_count_end\n"
output+="_byte_count_end:\n"
local tempfile=`mktemp /tmp/as_bytecount.XXXXXXXX`
echo "${output}" | as -arch "${CURRENT_ARCH}" -o "${tempfile}" -
if [ $? != 0 ]; then
echo "Assembling the trampoline failed"
exit 1
fi
local byte_size=`nm -t d -P "${tempfile}" | grep ^_byte_count_end | awk '{print $3}'`
rm -f "${tempfile}"
echo $byte_size
}
# Write out the page header
write_page_decl () {
# Calculate the required alignment
local align=`perl -l -e "print log(${PAGE_SIZE})/log(2)"`
asm << EOF
# GENERATED CODE - DO NOT EDIT"
# This file was generated by $PROGNAME on `date`
# Write out the trampoline table, aligned to the page boundary
.text
.align ${align}
.globl _${PAGE_NAME}
_${PAGE_NAME}:
EOF
}
main () {
echo '' > "${SRC_OUTPUT}"
echo '' > "${SRC_C_OUTPUT}"
echo '' > "${HEADER_OUTPUT}"
# Write out the trampoline header file
header "extern void *${PAGE_NAME};"
header "extern struct pl_trampoline_table_config ${PAGE_NAME}_config;"
# Don't generate the sources for the incorrect arch
if [ "${ARCH}" != "${CURRENT_ARCH}" ]; then
return
fi
# Determine the trampoline prefix size
trampoline_prefix
local prefix_size=$(compute_asm_size)
asm_discard
# Compute the size of the remaining code page.
local page_avail=`expr $PAGE_SIZE - $prefix_size`
# Determine the trampoline size
trampoline
local tramp_size=$(compute_asm_size)
asm_discard
if [ "${tramp_size}" = 0 ]; then
echo "Error occured calculating trampoline size; received size of 0"
exit 1
fi
# Compute the number of of available trampolines.
local trampoline_count=`expr $page_avail / $tramp_size`
echo "Prefix size: ${prefix_size}"
echo "Trampoline size: ${tramp_size}"
echo "Trampolines per page: ${trampoline_count}"
# Write out the page declaration
write_page_decl
asm_flush
# Write out the prefix
trampoline_prefix
asm_flush
# Write out the trampolines
trampoline
local i=0
while [ $i -lt ${trampoline_count} ]; do
asm_write
local i=`expr $i + 1`
done
asm_discard
# Write out the table configuration
local config_src=`cat << EOF
#include "trampoline_table.h"
extern void *${PAGE_NAME};
pl_trampoline_table_config ${PAGE_NAME}_config = {
.trampoline_size = ${tramp_size},
.page_offset = ${prefix_size},
.trampoline_count = ${trampoline_count},
.template_page = &${PAGE_NAME}
};
EOF`
src "${config_src}"
}
main
Jump to Line
Something went wrong with that request. Please try again.