Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 211 lines (176 sloc) 5.824 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 () {
if [ -e "${SRC_OUTPUT}" -a -e "${SRC_C_OUTPUT}" -a -e "${HEADER_OUTPUT}" ] ; then
return;
fi
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.