2018-05-26 00:30:22 +02:00
2018-05-26 00:33:26 +02:00
## Building the linux kernel from llvm bitcode requires writing scripts to copy, extract and recompile a lot of files in the right order.
## A script is only valid for one configuration of the kernel
2018-05-26 00:30:22 +02:00
2018-05-26 00:33:26 +02:00
## The goal of this Python script is to automate the script building process for any configuration of the kernel.
2018-05-26 00:30:22 +02:00
2018-05-26 00:33:26 +02:00
## It takes one or more argument : the first argument is where to write the final script, and all the others are paths to files of which we should not use the bitcode.
2018-05-26 00:30:22 +02:00
2018-05-26 00:33:26 +02:00
import sys , os
import subprocess
2018-05-26 00:30:22 +02:00
2018-05-26 00:33:26 +02:00
# This is where most of the script gets written.
# This function takes as argument:
# a list of path that should not be translated into bitcode
# the depth from the root (this is a recursive function)
# the path from the root to the current folder (its length should be depth)
def write_script ( excluded_paths , depth , base_dir ) :
builtin = open ( base_dir + " arbi " , " w " )
subprocess . call ( [ " ar " , " -t " , base_dir + " built-in.o " ] , stdout = builtin )
builtin . close ( )
builtin = open ( base_dir + " arbi " , " r " )
2018-05-26 00:30:22 +02:00
out . writelines ( " mkdir -p $build_home/built-ins/ " + base_dir + " \n " )
2018-05-26 00:33:26 +02:00
# In directories we store the list of depth 1 directories (and files) found in builtin
2018-05-26 00:30:22 +02:00
directories = [ ]
for line in builtin . readlines ( ) :
line = line . split ( ' \n ' ) [ 0 ]
words = line . split ( ' / ' )
2018-05-26 00:33:26 +02:00
if words [ 0 ] == " arch " : # We had to make an exception for the arch folder which does not have a built-in.o at the root.
2018-05-26 00:30:22 +02:00
words [ 0 ] = words [ 0 ] + ' / ' + words [ 1 ]
2018-05-26 00:33:26 +02:00
if words [ 2 ] in archbi : #A second exception for arch, not all files in the folder are referenced in the arch/x86/built-in.o. We store the exceptions in the archi list
2018-05-26 00:30:22 +02:00
words [ 0 ] = words [ 0 ] + ' / ' + words [ 2 ]
2018-05-26 00:33:26 +02:00
if words [ depth ] not in directories and line not in standalone_objects : #Some objects are not listed in a built-in.o except at the root, so we include them separately in order not to mess the order of linking
2018-05-26 00:30:22 +02:00
directories . append ( words [ depth ] )
2018-05-26 00:33:26 +02:00
# folders in which there are excluded folders which we will need to act on recursively
excluded_roots = [ path [ depth ] for path in excluded_paths ]
2018-05-26 00:30:22 +02:00
for direc in directories :
print base_dir + direc
2018-05-26 00:33:26 +02:00
# the folder contains an excluded folder
if direc in excluded_roots :
# Check if we have an excluded folder
2018-05-26 00:30:22 +02:00
if base_dir + direc in excluded_dirs :
out . writelines ( " convert-thin-archive.sh " + base_dir + direc + " /built-in.o \n " )
out . writelines ( " cp " + base_dir + direc + " /built-in.o.new $build_home/built-ins/ " + base_dir + direc + " bi.o \n \n " )
link_args . writelines ( " built-ins/ " + base_dir + direc + " bi.o " )
2018-05-26 00:33:26 +02:00
# Else we filter the excluded_path list for only relevant stuff and we call the recursion on that folder
2018-05-26 00:30:22 +02:00
else :
2018-05-26 00:33:26 +02:00
relevant_excluded = [ path for path in excluded_paths if ( path [ depth ] == direc and len ( path ) > depth + 1 ) ]
if relevant_excluded :
write_script ( relevant_excluded , depth + 1 , base_dir + direc + " / " )
2018-05-26 00:30:22 +02:00
else :
2018-05-26 00:33:26 +02:00
#If the "directory" is a file, we copy it into the relevant objects folder and compile it
2018-05-26 00:30:22 +02:00
if direc [ - 2 : ] == " .o " :
out . writelines ( " get-bc -b " + base_dir + direc + " \n " )
out . writelines ( " mkdir -p $build_home/built-ins/ " + base_dir + " objects \n " )
out . writelines ( " cp " + base_dir + direc + " .bc $build_home/built-ins/ " + base_dir + " objects \n " )
out . writelines ( " clang -c -no-integrated-as -mcmodel=kernel -o $build_home/built-ins/ " + base_dir + direc + " $build_home/built-ins/ " + base_dir + " objects/ " + direc + " .bc \n \n " )
2018-05-26 00:33:26 +02:00
# We then add it to the linker arguments file
2018-05-26 00:30:22 +02:00
link_args . writelines ( " built-ins/ " + base_dir + direc + " " )
2018-05-26 00:33:26 +02:00
# When dealing with a folder, we get the bitcode from the built-in.o file and check for errors in the log.
# For each file that does not have a bitcode version (compiled straight from assembly) we copy it into the build folder directly and add it to the linker args
2018-05-26 00:30:22 +02:00
else :
2018-05-26 00:33:26 +02:00
if os . path . isfile ( " /vagrant/wrapper-logs/wrapper.log " ) :
2018-06-15 02:45:43 +02:00
os . rename ( " /vagrant/wrapper-logs/wrapper.log " , " /vagrant/wrapper-logs/before_ " + direc . replace ( ' / ' , ' _ ' ) + " .log " )
2018-05-26 00:30:22 +02:00
path = base_dir + direc + " /built-in.o "
subprocess . call ( [ " get-bc " , " -b " , path ] )
2018-05-26 00:33:26 +02:00
subprocess . call ( [ " touch " , " /vagrant/wrapper-logs/wrapper.log " ] )
# Checking to see if any file failed to be extracted to bitcode
llvm_log = open ( " /vagrant/wrapper-logs/wrapper.log " , " r " )
2018-05-26 00:30:22 +02:00
assembly_objects = [ ]
for line in llvm_log . readlines ( ) :
if len ( line ) > = 54 and line [ : 54 ] == " WARNING:Error reading the .llvm_bc section of ELF file " :
assembly_objects . append ( line [ 55 : - 2 ] )
2018-05-26 00:33:26 +02:00
llvm_log . close ( )
# Deal with those files
2018-05-26 00:30:22 +02:00
if assembly_objects :
2018-06-15 02:45:43 +02:00
out . writelines ( " mkdir -p $build_home/built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + " \n " )
2018-05-26 00:30:22 +02:00
for asf in assembly_objects :
2018-06-15 02:45:43 +02:00
out . writelines ( " cp " + asf + " $build_home/built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + " \n " )
2018-05-26 00:30:22 +02:00
filename = asf . split ( ' / ' ) [ - 1 ]
2018-06-15 02:45:43 +02:00
link_args . writelines ( " built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + ' / ' + filename + " " )
2018-05-26 00:33:26 +02:00
# Deal with the rest
2018-05-26 00:30:22 +02:00
if os . path . isfile ( base_dir + direc + " /built-in.o.a.bc " ) :
2018-06-15 02:45:43 +02:00
out . writelines ( " cp " + base_dir + direc + " /built-in.o.a.bc $build_home/built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + " bi.o.bc \n " )
out . writelines ( " clang -c -no-integrated-as -mcmodel=kernel -o $build_home/built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + " bibc.o $build_home/built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + " bi.o.bc \n \n " )
link_args . writelines ( " built-ins/ " + base_dir + direc . replace ( ' / ' , ' _ ' ) + " bibc.o " )
2018-05-26 00:30:22 +02:00
builtin . close ( )
2018-05-26 00:33:26 +02:00
# excluded_dirs is a list where the folders excluded from bitcode translation will be stored
excluded_dirs = [ ]
if len ( sys . argv ) > 2 :
excluded_dirs = sys . argv [ 2 : ]
2018-06-15 02:45:43 +02:00
for path in excluded_dirs :
if path [ - 1 ] == ' / ' :
path = path [ : - 1 ]
2018-05-26 00:33:26 +02:00
2018-06-15 02:45:43 +02:00
# Output file pathlib
build_dir = sys . argv [ 1 ]
if build_dir [ - 1 ] != ' / ' :
build_dir + = ' / '
2018-05-26 00:33:26 +02:00
#We transform excluded_dirs into a 2D array for better access to individual folders in the path
excluded = [ path . split ( ' / ' ) for path in excluded_dirs ]
2018-06-15 02:45:43 +02:00
out = open ( " build_script.sh " , " w+ " )
link_args = open ( build_dir + " link-args " , " w+ " )
2018-05-26 00:33:26 +02:00
out . writelines ( " # Script written by the built-in-parsing.py script \n " )
2018-06-15 02:45:43 +02:00
out . writelines ( " export build_home= " + build_dir + " \n " )
2018-05-26 00:33:26 +02:00
# List exceptions
standalone_objects = [ " arch/x86/kernel/head_64.o " , " arch/x86/kernel/head64.o " , " arch/x86/kernel/ebda.o " , " arch/x86/kernel/platform-quirks.o " ] #,"usr/initramfs_data.o"]
archbi = [ " lib " , " pci " , " video " , " power " ]
# Calling the main function
write_script ( excluded , 0 , " " )
# Dealing with both lib files
2018-06-15 02:45:43 +02:00
out . writelines ( " get-bc -b lib/lib.a \n " )
out . writelines ( " mkdir -p $build_home/lib \n " )
out . writelines ( " cp lib/lib.a.bc $build_home/lib/ \n " )
2018-05-26 00:30:22 +02:00
out . writelines ( " clang -c -no-integrated-as -mcmodel=kernel -o $build_home/lib/lib.a.o $build_home/lib/lib.a.bc \n " )
2018-05-26 00:33:26 +02:00
if os . path . isfile ( " /vagrant/wrapper-logs/wrapper.log " ) :
os . rename ( " /vagrant/wrapper-logs/wrapper.log " , " /vagrant/wrapper-logs/before_lib.log " )
2018-06-15 02:45:43 +02:00
#os.remove("./wrapper-logs/wrapper.log")
out . writelines ( " mkdir -p $build_home/arch/x86/lib/objects \n " )
2018-05-26 00:30:22 +02:00
subprocess . call ( [ " get-bc " , " -b " , " arch/x86/lib/lib.a " ] )
2018-05-26 00:33:26 +02:00
subprocess . call ( [ " touch " , " /vagrant/wrapper-logs/wrapper.log " ] )
llvm_log = open ( " /vagrant/wrapper-logs/wrapper.log " , " r " )
2018-05-26 00:30:22 +02:00
assembly_objects = [ ]
for line in llvm_log . readlines ( ) :
2018-06-15 02:45:43 +02:00
if len ( line ) > = 55 and line [ : 54 ] == " WARNING:Error reading the .llvm_bc section of ELF file " :
2018-05-26 00:30:22 +02:00
assembly_objects . append ( line [ 55 : - 2 ] )
for asf in assembly_objects :
out . writelines ( " cp " + asf + " $build_home/arch/x86/lib/objects/ \n " )
filename = asf . split ( ' / ' ) [ - 1 ]
2018-06-15 02:45:43 +02:00
#link_args.writelines("arch/x86/lib/objects/" +filename+" ") ##ignored to keep the order of linked files
2018-05-26 00:30:22 +02:00
out . writelines ( " cp arch/x86/lib/lib.a.bc $build_home/arch/x86/lib/lib.a.bc \n " )
out . writelines ( " clang -c -no-integrated-as -mcmodel=kernel -o $build_home/arch/x86/lib/lib.a.o $build_home/arch/x86/lib/lib.a.bc \n \n " )
2018-05-26 00:33:26 +02:00
#Deal with individual files
2018-05-26 00:30:22 +02:00
out . writelines ( " cp arch/x86/kernel/vmlinux.lds $build_home \n " )
out . writelines ( " cp .tmp_kallsyms2.o $build_home \n " )
for sto in standalone_objects :
out . writelines ( " cp --parents " + sto + " $build_home \n " )
out . writelines ( " \n #linking command \n " )
2018-05-26 00:33:26 +02:00
2018-05-26 00:30:22 +02:00
out . writelines ( " cd $build_home \n " )
2018-05-26 00:33:26 +02:00
# Final linking command
2018-05-26 00:30:22 +02:00
out . writelines ( " ld --build-id -T vmlinux.lds --whole-archive " )
for sto in standalone_objects :
out . writelines ( sto + " " )
2018-06-16 01:25:32 +02:00
out . writelines ( " @link-args " )
2018-06-15 02:45:43 +02:00
out . writelines ( " --no-whole-archive --start-group lib/lib.a.o arch/x86/lib/lib.a.o arch/x86/lib/objects/* .tmp_kallsyms2.o --end-group -o vmlinux " )