mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
Refactor and add sparc (#454)
* Refactors the code to improve directory layout, use more std::string_view in place of std::string, deletes some deprecated functions, deprecates some other functions for eventual deletion, and includes semantics for sparcv8 (sparc32) and sparcv9 (sparc64) * Update new dir layout with llvm 11 support * Whoops missing files * Drop llvm 800 from workflow * Minor fix * Move where the install directives are in CMake * Minor fixes * Rename tools/ to bin/. * Minor tweaks * Should fix issues
This commit is contained in:
@@ -56,7 +56,7 @@ jobs:
|
||||
needs: [VersionFile]
|
||||
strategy:
|
||||
matrix:
|
||||
llvm: ["800", "900", "1000", "1100"]
|
||||
llvm: ["900", "1000", "1100"]
|
||||
ubuntu: ["20.04", "18.04"]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -18,6 +18,10 @@ Makefile
|
||||
CMakeLists.txt.user
|
||||
.vscode
|
||||
.idea
|
||||
.DS_Store
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
cmake-build-debug
|
||||
cmake-build-release
|
||||
compile_commands.json
|
||||
|
||||
+91
-232
@@ -31,7 +31,7 @@ if (LLVM_Z3_INSTALL_DIR)
|
||||
find_package(Z3 4.7.1)
|
||||
set(need_z3 TRUE)
|
||||
elseif(DEFINED CXX_COMMON_REPOSITORY_ROOT)
|
||||
set(LLVM_Z3_INSTALL_DIR "${CXX_COMMON_REPOSITORY_ROOT}/z3")
|
||||
set(LLVM_Z3_INSTALL_DIR "${CXX_COMMON_REPOSITORY_ROOT}/z3" CACHE PATH "Path to the z3 installation")
|
||||
set(need_z3 TRUE)
|
||||
else()
|
||||
set(need_z3 FALSE)
|
||||
@@ -54,15 +54,24 @@ set(REMILL_SOURCE_DIR "${PROJECT_SOURCE_DIR}")
|
||||
if(DEFINED WIN32)
|
||||
set(dynamic_lib_prefix "")
|
||||
set(dynamic_lib_extension "dll")
|
||||
set(static_lib_prefix "")
|
||||
set(static_lib_extension "lib")
|
||||
set(executable_extension ".exe")
|
||||
set(install_folder "${CMAKE_INSTALL_PREFIX}/remill")
|
||||
else()
|
||||
set(dynamic_lib_prefix "lib")
|
||||
set(dynamic_lib_extension "so")
|
||||
set(static_lib_prefix "lib")
|
||||
set(static_lib_extension "a")
|
||||
set(executable_extension "")
|
||||
set(install_folder "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
|
||||
set(REMILL_INSTALL_LIB_DIR "${install_folder}/lib" CACHE PATH "Directory in which remill libraries will be installed")
|
||||
set(REMILL_INSTALL_BIN_DIR "${install_folder}/bin" CACHE PATH "Directory in which remill binaries will be installed")
|
||||
set(REMILL_INSTALL_INCLUDE_DIR "${install_folder}/include" CACHE PATH "Directory in which remill headers will be installed")
|
||||
set(REMILL_INSTALL_SHARE_DIR "${install_folder}/share" CACHE PATH "Directory in which remill cmake files will be installed")
|
||||
|
||||
#
|
||||
# libraries
|
||||
#
|
||||
@@ -93,9 +102,6 @@ endforeach()
|
||||
# These are out-of-order in `LLVM_AVAILABLE_LIBS` and should always be last.
|
||||
list(REMOVE_ITEM LLVM_LIBRARIES LLVMMC LLVMCore LLVMSupport)
|
||||
list(APPEND LLVM_LIBRARIES LLVMMC LLVMCore LLVMSupport)
|
||||
message(WARNING "Libraries: ${LLVM_LIBRARIES}")
|
||||
|
||||
|
||||
target_link_libraries(thirdparty_llvm INTERFACE
|
||||
${LLVM_LIBRARIES}
|
||||
)
|
||||
@@ -143,6 +149,17 @@ if(DEFINED WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
# For Linux builds, group LLVM libraries into a single group
|
||||
# that avoids frustrating library ordering issues.
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(LINKER_START_GROUP "-Wl,--start-group")
|
||||
set(LINKER_END_GROUP "-Wl,--end-group")
|
||||
else()
|
||||
set(LINKER_START_GROUP "")
|
||||
set(LINKER_END_GROUP "")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Configuration options for semantics
|
||||
#
|
||||
@@ -156,65 +173,26 @@ set(REMILL_LLVM_VERSION "${LLVM_MAJOR_VERSION}.${LLVM_MINOR_VERSION}")
|
||||
math(EXPR REMILL_LLVM_VERSION_NUMBER "${LLVM_MAJOR_VERSION} * 100 + ${LLVM_MINOR_VERSION}")
|
||||
|
||||
if(DEFINED WIN32)
|
||||
set(REMILL_INSTALL_SEMANTICS_DIR "${install_folder}/${REMILL_LLVM_VERSION}/semantics/")
|
||||
set(REMILL_INSTALL_SEMANTICS_DIR "${install_folder}/${REMILL_LLVM_VERSION}/semantics" CACHE PATH "Directory into which semantics are installed")
|
||||
else()
|
||||
set(REMILL_INSTALL_SEMANTICS_DIR "${install_folder}/share/remill/${REMILL_LLVM_VERSION}/semantics/")
|
||||
set(REMILL_INSTALL_SEMANTICS_DIR "${REMILL_INSTALL_SHARE_DIR}/remill/${REMILL_LLVM_VERSION}/semantics" CACHE PATH "Directory into which semantics are installed")
|
||||
endif()
|
||||
|
||||
set(REMILL_BUILD_SEMANTICS_DIR_X86 "${CMAKE_CURRENT_BINARY_DIR}/remill/Arch/X86/Runtime/")
|
||||
set(REMILL_BUILD_SEMANTICS_DIR_AARCH64 "${CMAKE_CURRENT_BINARY_DIR}/remill/Arch/AArch64/Runtime/")
|
||||
set(REMILL_BUILD_SEMANTICS_DIR_X86 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/X86/Runtime")
|
||||
set(REMILL_BUILD_SEMANTICS_DIR_AARCH64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/AArch64/Runtime")
|
||||
set(REMILL_BUILD_SEMANTICS_DIR_SPARC32 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC32/Runtime")
|
||||
set(REMILL_BUILD_SEMANTICS_DIR_SPARC64 "${CMAKE_CURRENT_BINARY_DIR}/lib/Arch/SPARC64/Runtime")
|
||||
|
||||
# verion data
|
||||
add_subdirectory(remill/Version)
|
||||
set(REMILL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
set(REMILL_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")
|
||||
|
||||
add_library(remill STATIC
|
||||
remill/Arch/AArch64/Arch.cpp
|
||||
remill/Arch/AArch64/Decode.cpp
|
||||
remill/Arch/AArch64/Extract.cpp
|
||||
remill/Arch/X86/Arch.cpp
|
||||
add_library(remill_settings INTERFACE)
|
||||
|
||||
remill/Arch/Arch.cpp
|
||||
remill/Arch/Instruction.cpp
|
||||
remill/Arch/Name.cpp
|
||||
|
||||
remill/BC/Annotate.cpp
|
||||
remill/BC/DeadStoreEliminator.cpp
|
||||
remill/BC/IntrinsicTable.cpp
|
||||
remill/BC/Lifter.cpp
|
||||
remill/BC/Optimizer.cpp
|
||||
remill/BC/Util.cpp
|
||||
|
||||
remill/OS/Compat.cpp
|
||||
remill/OS/FileSystem.cpp
|
||||
remill/OS/OS.cpp
|
||||
)
|
||||
|
||||
set_property(TARGET remill PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set(THIRDPARTY_LIBRARY_LIST thirdparty_z3 thirdparty_llvm thirdparty_xed thirdparty_glog thirdparty_gflags)
|
||||
|
||||
# add everything as public.
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
#For Linux builds, group LLVM libraries into a single group
|
||||
# that avoids frustrating library ordering issues
|
||||
set(LINKER_START_GROUP "-Wl,--start-group")
|
||||
set(LINKER_END_GROUP "-Wl,--end-group")
|
||||
else()
|
||||
set(LINKER_START_GROUP "")
|
||||
set(LINKER_END_GROUP "")
|
||||
endif()
|
||||
|
||||
|
||||
target_link_libraries(remill LINK_PUBLIC
|
||||
${LINKER_START_GROUP} ${THIRDPARTY_LIBRARY_LIST} ${LINKER_END_GROUP}
|
||||
RemillVersion
|
||||
)
|
||||
|
||||
target_include_directories(remill PUBLIC ${CMAKE_SOURCE_DIR})
|
||||
target_include_directories(remill_settings INTERFACE "${REMILL_INCLUDE_DIR}")
|
||||
|
||||
if(WIN32)
|
||||
# warnings and compiler settings
|
||||
target_compile_options(remill PUBLIC
|
||||
target_compile_options(remill_settings INTERFACE
|
||||
/MD /nologo /W3 /EHsc /wd4141 /wd4146 /wd4180 /wd4244
|
||||
/wd4258 /wd4267 /wd4291 /wd4345 /wd4351 /wd4355 /wd4456
|
||||
/wd4457 /wd4458 /wd4459 /wd4503 /wd4624 /wd4722 /wd4800
|
||||
@@ -223,7 +201,7 @@ if(WIN32)
|
||||
/wd4805 /wd4204 /wd4577 /wd4091 /wd4592 /wd4324
|
||||
)
|
||||
|
||||
target_compile_definitions(remill PUBLIC
|
||||
target_compile_definitions(remill_settings INTERFACE
|
||||
_CRT_SECURE_NO_DEPRECATE
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
_CRT_NONSTDC_NO_DEPRECATE
|
||||
@@ -235,7 +213,7 @@ if(WIN32)
|
||||
|
||||
else()
|
||||
# warnings and compiler settings
|
||||
target_compile_options(remill PUBLIC
|
||||
target_compile_options(remill_settings INTERFACE
|
||||
-Wall -Wextra -Wno-unused-parameter -Wno-c++98-compat
|
||||
-Wno-unreachable-code-return -Wno-nested-anon-types
|
||||
-Wno-extended-offsetof
|
||||
@@ -248,7 +226,7 @@ else()
|
||||
|
||||
# Clang-specific warnings/error options
|
||||
if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
target_compile_options(remill PUBLIC
|
||||
target_compile_options(remill_settings INTERFACE
|
||||
-Wgnu-alignof-expression -Wno-gnu-anonymous-struct -Wno-gnu-designator
|
||||
-Wno-gnu-zero-variadic-macro-arguments -Wno-gnu-statement-expression
|
||||
-fno-aligned-allocation
|
||||
@@ -257,106 +235,67 @@ else()
|
||||
|
||||
# debug symbols
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
target_compile_options(remill PUBLIC
|
||||
target_compile_options(remill_settings INTERFACE
|
||||
-gdwarf-2 -g3
|
||||
)
|
||||
endif()
|
||||
|
||||
# optimization flags and definitions
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_options(remill PUBLIC
|
||||
target_compile_options(remill_settings INTERFACE
|
||||
-O0
|
||||
)
|
||||
target_compile_definitions(remill PUBLIC
|
||||
target_compile_definitions(remill_settings INTERFACE
|
||||
"DEBUG"
|
||||
)
|
||||
else()
|
||||
target_compile_options(remill PUBLIC
|
||||
target_compile_options(remill_settings INTERFACE
|
||||
-O2
|
||||
)
|
||||
target_compile_definitions(remill PUBLIC
|
||||
target_compile_definitions(remill_settings INTERFACE
|
||||
"NDEBUG"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(remill PUBLIC
|
||||
target_compile_definitions(remill_settings INTERFACE
|
||||
"REMILL_INSTALL_SEMANTICS_DIR=\"${REMILL_INSTALL_SEMANTICS_DIR}/\""
|
||||
"REMILL_BUILD_SEMANTICS_DIR_X86=\"${REMILL_BUILD_SEMANTICS_DIR_X86}\""
|
||||
"REMILL_BUILD_SEMANTICS_DIR_AARCH64=\"${REMILL_BUILD_SEMANTICS_DIR_AARCH64}\""
|
||||
"REMILL_BUILD_SEMANTICS_DIR_SPARC32=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC32}\""
|
||||
"REMILL_BUILD_SEMANTICS_DIR_SPARC64=\"${REMILL_BUILD_SEMANTICS_DIR_SPARC64}\""
|
||||
)
|
||||
|
||||
set(THIRDPARTY_LIBRARY_LIST thirdparty_z3
|
||||
thirdparty_llvm
|
||||
thirdparty_xed
|
||||
thirdparty_glog
|
||||
thirdparty_gflags)
|
||||
|
||||
target_link_libraries(remill_settings INTERFACE
|
||||
${THIRDPARTY_LIBRARY_LIST}
|
||||
)
|
||||
|
||||
add_subdirectory(lib/Arch)
|
||||
add_subdirectory(lib/BC)
|
||||
add_subdirectory(lib/OS)
|
||||
add_subdirectory(lib/Version)
|
||||
|
||||
add_library(remill INTERFACE)
|
||||
target_link_libraries(remill INTERFACE
|
||||
${LINKER_START_GROUP}
|
||||
${THIRDPARTY_LIBRARY_LIST}
|
||||
remill_bc
|
||||
remill_os
|
||||
remill_arch
|
||||
remill_version
|
||||
${LINKER_END_GROUP}
|
||||
)
|
||||
|
||||
#
|
||||
# Also install clang, libllvm and llvm-link
|
||||
#
|
||||
|
||||
function(InstallExternalTarget target_name target_path install_directory installed_file_name)
|
||||
# Get the optional rpath parameter
|
||||
set(additional_arguments ${ARGN})
|
||||
list(LENGTH additional_arguments additional_argument_count)
|
||||
|
||||
if("${additional_argument_count}" EQUAL 0)
|
||||
elseif("${additional_argument_count}" EQUAL 1)
|
||||
list(GET additional_arguments 0 rpath)
|
||||
else()
|
||||
message(FATAL_ERROR "InstallExternalTarget: Invalid argument count")
|
||||
endif()
|
||||
|
||||
# We need to locate the patchelf executable to fix the rpath; search for it
|
||||
# only once, and then export the variable with PARENT_SCOPE so that we can
|
||||
# re-use it in the next calls
|
||||
if(NOT "${rpath}" STREQUAL "")
|
||||
if("${PATCHELF_LOCATION}" STREQUAL "")
|
||||
find_program("program_location" "patchelf")
|
||||
if("${program_location}" STREQUAL "program_location-NOTFOUND")
|
||||
message(FATAL_ERROR "InstallExternalTarget: Failed to locate the patchelf executable")
|
||||
endif()
|
||||
|
||||
# We need to set it both in local and in parent scope
|
||||
set("PATCHELF_LOCATION" "${program_location}" PARENT_SCOPE)
|
||||
set("PATCHELF_LOCATION" "${program_location}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Make sure the parameters are correct
|
||||
if(NOT EXISTS "${target_path}")
|
||||
message(FATAL_ERROR "InstallExternalTarget: The following path does not exists: ${target_path}")
|
||||
endif()
|
||||
|
||||
if("${target_name}")
|
||||
message(FATAL_ERROR "InstallExternalTarget: The following target already exists: ${target_name}")
|
||||
endif()
|
||||
|
||||
if("${install_directory}" STREQUAL "")
|
||||
message(FATAL_ERROR "InstallExternalTarget: Invalid install directory specified")
|
||||
endif()
|
||||
|
||||
# Generate the target
|
||||
set("output_file_path" "${CMAKE_CURRENT_BINARY_DIR}/${installed_file_name}")
|
||||
|
||||
if(NOT "${rpath}" STREQUAL "")
|
||||
set(CHRPATH_COMMAND ${PATCHELF_LOCATION} --set-rpath ${rpath} ${output_file_path})
|
||||
else()
|
||||
set(CHRPATH_COMMAND ${CMAKE_COMMAND} -E echo 'No rpath patch needed for ${target_name}')
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${output_file_path}"
|
||||
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${target_path} ${output_file_path}
|
||||
COMMAND ${CHRPATH_COMMAND}
|
||||
)
|
||||
|
||||
add_custom_target("${target_name}" ALL DEPENDS "${output_file_path}")
|
||||
|
||||
install(FILES "${output_file_path}"
|
||||
DESTINATION "${install_directory}"
|
||||
PERMISSIONS OWNER_READ OWNER_EXECUTE
|
||||
GROUP_READ GROUP_EXECUTE
|
||||
WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
set(INSTALLED_CLANG_NAME "remill-clang-${REMILL_LLVM_VERSION}${executable_extension}")
|
||||
set(INSTALLED_LLVMLINK_NAME "remill-llvm-link-${REMILL_LLVM_VERSION}${executable_extension}")
|
||||
|
||||
@@ -385,31 +324,35 @@ if("${CXX_COMMON_REPOSITORY_ROOT}" STREQUAL "" OR NOT EXISTS "${CXX_COMMON_REPOS
|
||||
|
||||
message("InstallExternalTarget: Found libLLVM location: ${libllvm_location}")
|
||||
|
||||
InstallExternalTarget("ext_clang" "${clang_location}" "${install_folder}/bin"
|
||||
"${INSTALLED_CLANG_NAME}" "${install_folder}/lib")
|
||||
InstallExternalTarget("ext_clang" "${clang_location}" "${REMILL_INSTALL_BIN_DIR}"
|
||||
"${INSTALLED_CLANG_NAME}" "${REMILL_INSTALL_LIB_DIR}")
|
||||
|
||||
InstallExternalTarget("ext_llvmlink" "${llvmlink_location}" "${install_folder}/bin"
|
||||
"${INSTALLED_LLVMLINK_NAME}" "${install_folder}/lib")
|
||||
InstallExternalTarget("ext_llvmlink" "${llvmlink_location}" "${REMILL_INSTALL_BIN_DIR}"
|
||||
"${INSTALLED_LLVMLINK_NAME}" "${REMILL_INSTALL_LIB_DIR}")
|
||||
|
||||
else()
|
||||
# The executable in our binary repository are statically built, meaning that we don't need
|
||||
# to change the rpath
|
||||
InstallExternalTarget("ext_clang" "${CXX_COMMON_REPOSITORY_ROOT}/llvm/bin/clang${executable_extension}"
|
||||
"${install_folder}/bin" "${INSTALLED_CLANG_NAME}")
|
||||
"${REMILL_INSTALL_BIN_DIR}" "${INSTALLED_CLANG_NAME}")
|
||||
|
||||
InstallExternalTarget("ext_llvmlink" "${CXX_COMMON_REPOSITORY_ROOT}/llvm/bin/llvm-link${executable_extension}"
|
||||
"${install_folder}/bin" "${INSTALLED_LLVMLINK_NAME}")
|
||||
"${REMILL_INSTALL_BIN_DIR}" "${INSTALLED_LLVMLINK_NAME}")
|
||||
endif()
|
||||
|
||||
install(TARGETS "${PROJECT_NAME}"
|
||||
ARCHIVE DESTINATION "${install_folder}/lib"
|
||||
PUBLIC_HEADER DESTINATION "${install_folder}/include"
|
||||
)
|
||||
set(REMILL_BC_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_bc.${static_lib_extension}")
|
||||
set(REMILL_ARCH_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch.${static_lib_extension}")
|
||||
set(REMILL_ARCH_X86_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_x86.${static_lib_extension}")
|
||||
set(REMILL_ARCH_AARCH64_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_aarch64.${static_lib_extension}")
|
||||
set(REMILL_ARCH_SPARC32_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_sparc32.${static_lib_extension}")
|
||||
set(REMILL_ARCH_SPARC64_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_arch_sparc64.${static_lib_extension}")
|
||||
set(REMILL_OS_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_os.${static_lib_extension}")
|
||||
set(REMILL_VERSION_LIBRARY_LOCATION "${REMILL_INSTALL_LIB_DIR}/${static_lib_prefix}remill_version.${static_lib_extension}")
|
||||
|
||||
set(REMILL_LIBRARY_LOCATION "${install_folder}/lib/libremill.a")
|
||||
set(REMILL_INCLUDE_LOCATION "${install_folder}/include")
|
||||
get_target_property(REMILL_COMPILE_OPTIONS remill COMPILE_OPTIONS)
|
||||
get_target_property(REMILL_COMPILE_DEFINITIONS remill COMPILE_DEFINITIONS)
|
||||
|
||||
set(REMILL_INCLUDE_LOCATION "${REMILL_INSTALL_INCLUDE_DIR}")
|
||||
get_target_property(REMILL_COMPILE_OPTIONS remill_settings INTERFACE_COMPILE_OPTIONS)
|
||||
get_target_property(REMILL_COMPILE_DEFINITIONS remill_settings INTERFACE_COMPILE_DEFINITIONS)
|
||||
|
||||
GetTargetTree(THIRDPARTY_LIBRARIES ${THIRDPARTY_LIBRARY_LIST})
|
||||
GetPublicIncludeFolders(THIRDPARTY_INCLUDE_DIRECTORIES ${THIRDPARTY_LIBRARIES})
|
||||
@@ -428,10 +371,6 @@ foreach(THIRDPARTY_LIB IN LISTS THIRDPARTY_LIBRARIES)
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES THIRDPARTY_LIBRARY_FILES)
|
||||
if(NOT "x{$LINKER_START_GROUP}x" STREQUAL "xx")
|
||||
list(INSERT THIRDPARTY_LIBRARY_FILES 0 "${LINKER_START_GROUP}")
|
||||
list(APPEND THIRDPARTY_LIBRARY_FILES "${LINKER_END_GROUP}")
|
||||
endif()
|
||||
|
||||
# First do the basic substitutions.
|
||||
configure_file(
|
||||
@@ -447,87 +386,11 @@ file(GENERATE
|
||||
)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/remillConfig.cmake"
|
||||
DESTINATION "${install_folder}/lib/cmake/remill"
|
||||
DESTINATION "${REMILL_INSTALL_LIB_DIR}/cmake/remill"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Arch.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Instruction.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Name.h"
|
||||
|
||||
DESTINATION "${install_folder}/include/remill/Arch"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/ABI.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Annotate.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/DeadStoreEliminator.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/IntrinsicTable.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Lifter.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Optimizer.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Util.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Version.h"
|
||||
|
||||
DESTINATION "${install_folder}/include/remill/BC"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/Attributes.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/BitcodeReaderWriter.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/CallingConvention.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/CTypes.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/DataLayout.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/DebugInfo.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/Error.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/FileSystem.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/GlobalValue.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/IRReader.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/JITSymbol.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/RuntimeDyld.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/ScalarTransforms.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/TargetLibraryInfo.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/ToolOutputFile.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/BC/Compat/Verifier.h"
|
||||
|
||||
DESTINATION "${install_folder}/include/remill/BC/Compat"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/OS/OS.h"
|
||||
DESTINATION "${install_folder}/include/remill/OS"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/Definitions.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/HyperCall.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/Intrinsics.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/Operators.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/Runtime.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/State.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/Runtime/Types.h"
|
||||
|
||||
DESTINATION "${install_folder}/include/remill/Arch/Runtime"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/X86/Runtime/State.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/X86/Runtime/Types.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/X86/Runtime/Operators.h"
|
||||
|
||||
DESTINATION "${install_folder}/include/remill/Arch/X86/Runtime"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/AArch64/Runtime/State.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/AArch64/Runtime/Types.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Arch/AArch64/Runtime/Operators.h"
|
||||
|
||||
DESTINATION "${install_folder}/include/remill/Arch/AArch64/Runtime"
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remill/Version/Version.h"
|
||||
DESTINATION "${install_folder}/include/remill/Version"
|
||||
install(DIRECTORY "${REMILL_INCLUDE_DIR}/remill"
|
||||
DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}"
|
||||
)
|
||||
|
||||
#
|
||||
@@ -536,12 +399,8 @@ install(FILES
|
||||
|
||||
add_custom_target(semantics)
|
||||
|
||||
# runtimes
|
||||
add_subdirectory(remill/Arch/X86/Runtime)
|
||||
add_subdirectory(remill/Arch/AArch64/Runtime)
|
||||
|
||||
# tools
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(bin)
|
||||
|
||||
# tests
|
||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
||||
|
||||
@@ -12,7 +12,5 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if(EXISTS ${CMAKE_SOURCE_DIR}/tools/lift)
|
||||
add_subdirectory(lift)
|
||||
endif()
|
||||
add_subdirectory(lift)
|
||||
|
||||
@@ -29,17 +29,11 @@ add_executable(${REMILL_LIFT}
|
||||
# target settings
|
||||
#
|
||||
|
||||
target_link_libraries(${REMILL_LIFT} PRIVATE remill RemillVersion)
|
||||
target_link_libraries(${REMILL_LIFT} PRIVATE remill)
|
||||
target_include_directories(${REMILL_LIFT} SYSTEM PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
if(DEFINED WIN32)
|
||||
set(install_folder "${CMAKE_INSTALL_PREFIX}/remill")
|
||||
else()
|
||||
set(install_folder "${CMAKE_INSTALL_PREFIX}")
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS ${REMILL_LIFT}
|
||||
RUNTIME DESTINATION "${install_folder}/bin"
|
||||
LIBRARY DESTINATION "${install_folder}/lib"
|
||||
RUNTIME DESTINATION "${REMILL_INSTALL_BIN_DIR}"
|
||||
LIBRARY DESTINATION "${REMILL_INSTALL_LIB_DIR}"
|
||||
)
|
||||
@@ -47,6 +47,9 @@
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
DECLARE_string(arch);
|
||||
DECLARE_string(os);
|
||||
|
||||
DEFINE_uint64(address, 0,
|
||||
"Address at which we should assume the bytes are"
|
||||
"located in virtual memory.");
|
||||
@@ -182,23 +185,23 @@ static void MuteStateEscape(llvm::Module *module, const char *func_name) {
|
||||
}
|
||||
}
|
||||
|
||||
static void SetVersion() {
|
||||
static void SetVersion(void) {
|
||||
std::stringstream ss;
|
||||
auto vs = remill::Version::GetVersionString();
|
||||
auto vs = remill::version::GetVersionString();
|
||||
if (0 == vs.size()) {
|
||||
vs = "unknown";
|
||||
}
|
||||
ss << vs << "\n";
|
||||
if (!remill::Version::HasVersionData()) {
|
||||
if (!remill::version::HasVersionData()) {
|
||||
ss << "No extended version information found!\n";
|
||||
} else {
|
||||
ss << "Commit Hash: " << remill::Version::GetCommitHash() << "\n";
|
||||
ss << "Commit Date: " << remill::Version::GetCommitDate() << "\n";
|
||||
ss << "Last commit by: " << remill::Version::GetAuthorName() << " ["
|
||||
<< remill::Version::GetAuthorEmail() << "]\n";
|
||||
ss << "Commit Subject: [" << remill::Version::GetCommitSubject() << "]\n";
|
||||
ss << "Commit Hash: " << remill::version::GetCommitHash() << "\n";
|
||||
ss << "Commit Date: " << remill::version::GetCommitDate() << "\n";
|
||||
ss << "Last commit by: " << remill::version::GetAuthorName() << " ["
|
||||
<< remill::version::GetAuthorEmail() << "]\n";
|
||||
ss << "Commit Subject: [" << remill::version::GetCommitSubject() << "]\n";
|
||||
ss << "\n";
|
||||
if (remill::Version::HasUncommittedChanges()) {
|
||||
if (remill::version::HasUncommittedChanges()) {
|
||||
ss << "Uncommitted changes were present during build.\n";
|
||||
} else {
|
||||
ss << "All changes were committed prior to building.\n";
|
||||
@@ -232,7 +235,7 @@ int main(int argc, char *argv[]) {
|
||||
// Make sure `--address` and `--entry_address` are in-bounds for the target
|
||||
// architecture's address size.
|
||||
llvm::LLVMContext context;
|
||||
auto arch = remill::Arch::GetTargetArch(context);
|
||||
auto arch = remill::Arch::Get(context, FLAGS_os, FLAGS_arch);
|
||||
const uint64_t addr_mask = ~0ULL >> (64UL - arch->address_size);
|
||||
if (FLAGS_address != (FLAGS_address & addr_mask)) {
|
||||
std::cerr << "Value " << std::hex << FLAGS_address
|
||||
@@ -251,8 +254,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
std::unique_ptr<llvm::Module> module(remill::LoadArchSemantics(arch));
|
||||
|
||||
const auto state_ptr_type = remill::StatePointerType(module.get());
|
||||
const auto mem_ptr_type = remill::MemoryPointerType(module.get());
|
||||
const auto state_ptr_type = arch->StatePointerType();
|
||||
const auto mem_ptr_type = arch->MemoryPointerType();
|
||||
|
||||
Memory memory = UnhexlifyInputBytes(addr_mask);
|
||||
SimpleTraceManager manager(memory);
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2017 Trail of Bits, Inc.
|
||||
# Copyright (c) 2020 Trail of Bits, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -22,22 +22,80 @@ if(NOT TARGET remill)
|
||||
set(REMILL_LIBRARY_LOCATION "@CMAKE_INSTALL_PREFIX@/lib/libremill.a")
|
||||
set(REMILL_INCLUDE_LOCATION "@CMAKE_INSTALL_PREFIX@/include")
|
||||
endif()
|
||||
|
||||
# For Linux builds, group LLVM libraries into a single group
|
||||
# that avoids frustrating library ordering issues.
|
||||
if(UNIX AND NOT APPLE)
|
||||
set(LINKER_START_GROUP "-Wl,--start-group")
|
||||
set(LINKER_END_GROUP "-Wl,--end-group")
|
||||
else()
|
||||
set(LINKER_START_GROUP "")
|
||||
set(LINKER_END_GROUP "")
|
||||
endif()
|
||||
|
||||
if(NOT "x@CXX_COMMON_REPOSITORY_ROOT@x" STREQUAL "xx")
|
||||
set(CXX_COMMON_REPOSITORY_ROOT "@CXX_COMMON_REPOSITORY_ROOT@")
|
||||
if (EXISTS "@CXX_COMMON_REPOSITORY_ROOT@")
|
||||
set(CXX_COMMON_REPOSITORY_ROOT "@CXX_COMMON_REPOSITORY_ROOT@"
|
||||
CACHE PATH "Location of cxx-common libraries"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CXX_COMMON_REPOSITORY_ROOT OR NOT EXISTS "${CXX_COMMON_REPOSITORY_ROOT}")
|
||||
if(DEFINED ENV{TRAILOFBITS_LIBRARIES})
|
||||
set(CXX_COMMON_REPOSITORY_ROOT $ENV{TRAILOFBITS_LIBRARIES}
|
||||
CACHE PATH "Location of cxx-common libraries."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LLVM_MAJOR_VERSION @LLVM_MAJOR_VERSION@)
|
||||
set(LLVM_MINOR_VERSION @LLVM_MINOR_VERSION@)
|
||||
set(REMILL_LLVM_VERSION "@LLVM_MAJOR_VERSION@.@LLVM_MINOR_VERSION@")
|
||||
|
||||
add_library(remill STATIC IMPORTED)
|
||||
set_property(TARGET remill PROPERTY IMPORTED_LOCATION "@REMILL_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_bc STATIC IMPORTED)
|
||||
set_property(TARGET remill_bc PROPERTY IMPORTED_LOCATION "@REMILL_BC_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_os STATIC IMPORTED)
|
||||
set_property(TARGET remill_os PROPERTY IMPORTED_LOCATION "@REMILL_OS_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_arch STATIC IMPORTED)
|
||||
set_property(TARGET remill_arch PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_arch_x86 STATIC IMPORTED)
|
||||
set_property(TARGET remill_arch_x86 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_X86_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_arch_aarch64 STATIC IMPORTED)
|
||||
set_property(TARGET remill_arch_aarch64 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_AARCH64_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_arch_sparc32 STATIC IMPORTED)
|
||||
set_property(TARGET remill_arch_sparc32 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_SPARC32_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_arch_sparc64 STATIC IMPORTED)
|
||||
set_property(TARGET remill_arch_sparc64 PROPERTY IMPORTED_LOCATION "@REMILL_ARCH_SPARC64_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill_version STATIC IMPORTED)
|
||||
set_property(TARGET remill_version PROPERTY IMPORTED_LOCATION "@REMILL_VERSION_LIBRARY_LOCATION@")
|
||||
|
||||
add_library(remill INTERFACE)
|
||||
target_link_libraries(remill INTERFACE
|
||||
${LINKER_START_GROUP}
|
||||
remill_bc
|
||||
remill_os
|
||||
remill_arch
|
||||
remill_arch_x86
|
||||
remill_arch_aarch64
|
||||
remill_arch_sparc32
|
||||
remill_arch_sparc64
|
||||
remill_version
|
||||
@THIRDPARTY_LIBRARY_FILES@
|
||||
${LINKER_END_GROUP}
|
||||
)
|
||||
|
||||
target_include_directories(remill INTERFACE @THIRDPARTY_INCLUDE_DIRECTORIES@)
|
||||
target_include_directories(remill INTERFACE @REMILL_INCLUDE_LOCATION@)
|
||||
target_compile_options(remill INTERFACE @REMILL_COMPILE_OPTIONS@)
|
||||
target_compile_definitions(remill INTERFACE @REMILL_COMPILE_DEFINITIONS@)
|
||||
target_link_libraries(remill INTERFACE @THIRDPARTY_LIBRARY_FILES@)
|
||||
|
||||
# Add a dummy 'semantics' target to satisfy the protobuf generator
|
||||
add_custom_target(semantics)
|
||||
|
||||
@@ -27,11 +27,13 @@ macro(main)
|
||||
#
|
||||
# cxx-common
|
||||
#
|
||||
|
||||
if(DEFINED ENV{TRAILOFBITS_LIBRARIES})
|
||||
set(CXX_COMMON_REPOSITORY_ROOT $ENV{TRAILOFBITS_LIBRARIES}
|
||||
CACHE PATH "Location of cxx-common libraries."
|
||||
)
|
||||
|
||||
if(NOT DEFINED CXX_COMMON_REPOSITORY_ROOT)
|
||||
if(DEFINED ENV{TRAILOFBITS_LIBRARIES})
|
||||
set(CXX_COMMON_REPOSITORY_ROOT $ENV{TRAILOFBITS_LIBRARIES}
|
||||
CACHE PATH "Location of cxx-common libraries."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DEFINED CXX_COMMON_REPOSITORY_ROOT)
|
||||
|
||||
@@ -157,3 +157,71 @@ function(GetPublicIncludeFolders output_variable)
|
||||
list(REMOVE_DUPLICATES collected_include_dirs)
|
||||
set("${output_variable}" ${collected_include_dirs} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(InstallExternalTarget target_name target_path install_directory installed_file_name)
|
||||
# Get the optional rpath parameter
|
||||
set(additional_arguments ${ARGN})
|
||||
list(LENGTH additional_arguments additional_argument_count)
|
||||
|
||||
if("${additional_argument_count}" EQUAL 0)
|
||||
elseif("${additional_argument_count}" EQUAL 1)
|
||||
list(GET additional_arguments 0 rpath)
|
||||
else()
|
||||
message(FATAL_ERROR "InstallExternalTarget: Invalid argument count")
|
||||
endif()
|
||||
|
||||
# We need to locate the patchelf executable to fix the rpath; search for it
|
||||
# only once, and then export the variable with PARENT_SCOPE so that we can
|
||||
# re-use it in the next calls
|
||||
if(NOT "${rpath}" STREQUAL "")
|
||||
if("${PATCHELF_LOCATION}" STREQUAL "")
|
||||
find_program("program_location" "patchelf")
|
||||
if("${program_location}" STREQUAL "program_location-NOTFOUND")
|
||||
message(FATAL_ERROR "InstallExternalTarget: Failed to locate the patchelf executable")
|
||||
endif()
|
||||
|
||||
# We need to set it both in local and in parent scope
|
||||
set("PATCHELF_LOCATION" "${program_location}" PARENT_SCOPE)
|
||||
set("PATCHELF_LOCATION" "${program_location}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Make sure the parameters are correct
|
||||
if(NOT EXISTS "${target_path}")
|
||||
message(FATAL_ERROR "InstallExternalTarget: The following path does not exists: ${target_path}")
|
||||
endif()
|
||||
|
||||
if("${target_name}")
|
||||
message(FATAL_ERROR "InstallExternalTarget: The following target already exists: ${target_name}")
|
||||
endif()
|
||||
|
||||
if("${install_directory}" STREQUAL "")
|
||||
message(FATAL_ERROR "InstallExternalTarget: Invalid install directory specified")
|
||||
endif()
|
||||
|
||||
# Generate the target
|
||||
set("output_file_path" "${CMAKE_CURRENT_BINARY_DIR}/${installed_file_name}")
|
||||
|
||||
if(NOT "${rpath}" STREQUAL "")
|
||||
set(CHRPATH_COMMAND ${PATCHELF_LOCATION} --set-rpath ${rpath} ${output_file_path})
|
||||
else()
|
||||
set(CHRPATH_COMMAND ${CMAKE_COMMAND} -E echo 'No rpath patch needed for ${target_name}')
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${output_file_path}"
|
||||
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy ${target_path} ${output_file_path}
|
||||
COMMAND ${CHRPATH_COMMAND}
|
||||
)
|
||||
|
||||
add_custom_target("${target_name}" ALL DEPENDS "${output_file_path}")
|
||||
|
||||
install(FILES "${output_file_path}"
|
||||
DESTINATION "${install_directory}"
|
||||
PERMISSIONS OWNER_READ OWNER_EXECUTE
|
||||
GROUP_READ GROUP_EXECUTE
|
||||
WORLD_READ WORLD_EXECUTE
|
||||
)
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -125,12 +125,20 @@ class Arch {
|
||||
|
||||
// Factory method for loading the correct architecture class for a given
|
||||
// operating system and architecture class.
|
||||
static const Arch *Get(llvm::LLVMContext &context, OSName os,
|
||||
ArchName arch_name);
|
||||
static auto Get(llvm::LLVMContext &context, std::string_view os,
|
||||
std::string_view arch_name) -> ArchPtr;
|
||||
|
||||
// Factory method for loading the correct architecture class for a given
|
||||
// operating system and architecture class.
|
||||
static auto Get(llvm::LLVMContext &context, OSName os,
|
||||
ArchName arch_name) -> ArchPtr;
|
||||
|
||||
// Return the type of the state structure.
|
||||
llvm::StructType *StateStructType(void) const;
|
||||
|
||||
// Pointer to a state structure type.
|
||||
llvm::PointerType *StatePointerType(void) const;
|
||||
|
||||
// Return the type of an address, i.e. `addr_t` in the semantics.
|
||||
llvm::IntegerType *AddressType(void) const;
|
||||
|
||||
@@ -148,13 +156,13 @@ class Arch {
|
||||
const Register *RegisterAtStateOffset(uint64_t offset) const;
|
||||
|
||||
// Return information about a register, given its name.
|
||||
const Register *RegisterByName(const std::string &name) const;
|
||||
const Register *RegisterByName(std::string_view name) const;
|
||||
|
||||
// Returns the name of the stack pointer register.
|
||||
virtual const char *StackPointerRegisterName(void) const = 0;
|
||||
virtual std::string_view StackPointerRegisterName(void) const = 0;
|
||||
|
||||
// Returns the name of the program counter register.
|
||||
virtual const char *ProgramCounterRegisterName(void) const = 0;
|
||||
virtual std::string_view ProgramCounterRegisterName(void) const = 0;
|
||||
|
||||
// Converts an LLVM module object to have the right triple / data layout
|
||||
// information for the target architecture and ensures remill requied functions
|
||||
@@ -237,6 +245,8 @@ class Arch {
|
||||
bool IsX86(void) const;
|
||||
bool IsAMD64(void) const;
|
||||
bool IsAArch64(void) const;
|
||||
bool IsSPARC32(void) const;
|
||||
bool IsSPARC64(void) const;
|
||||
|
||||
bool IsWindows(void) const;
|
||||
bool IsLinux(void) const;
|
||||
@@ -249,7 +259,8 @@ class Arch {
|
||||
|
||||
// Get the architecture of the modelled code. This is based on command-line
|
||||
// flags. Rather use directly Build.
|
||||
static ArchPtr GetTargetArch(llvm::LLVMContext &context);
|
||||
static ArchPtr GetTargetArch(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Get the (approximate) architecture of the system library was built on. This may not
|
||||
// include all feature sets.
|
||||
@@ -265,32 +276,30 @@ class Arch {
|
||||
llvm::Triple BasicTriple(void) const;
|
||||
|
||||
// Add a register into this
|
||||
void AddRegister(const char *reg_name, llvm::Type *val_type, size_t offset,
|
||||
const char *parent_reg_name) const;
|
||||
const Register *AddRegister(const char *reg_name,
|
||||
llvm::Type *val_type, size_t offset,
|
||||
const char *parent_reg_name) const;
|
||||
|
||||
private:
|
||||
// Defined in `remill/Arch/X86/Arch.cpp`.
|
||||
// Defined in `lib/Arch/X86/Arch.cpp`.
|
||||
static ArchPtr GetX86(llvm::LLVMContext *context, OSName os,
|
||||
ArchName arch_name);
|
||||
|
||||
// Defined in `remill/Arch/AArch64/Arch.cpp`.
|
||||
// Defined in `lib/Arch/AArch64/Arch.cpp`.
|
||||
static ArchPtr GetAArch64(llvm::LLVMContext *context, OSName os,
|
||||
ArchName arch_name);
|
||||
|
||||
// Defined in `lib/Arch/SPARC32/Arch.cpp`.
|
||||
static ArchPtr GetSPARC(
|
||||
llvm::LLVMContext *context, OSName os, ArchName arch_name);
|
||||
|
||||
// Defined in `lib/Arch/SPARC64/Arch.cpp`.
|
||||
static ArchPtr GetSPARC64(
|
||||
llvm::LLVMContext *context, OSName os, ArchName arch_name);
|
||||
|
||||
mutable std::unique_ptr<ArchImpl> impl;
|
||||
|
||||
Arch(void) = delete;
|
||||
};
|
||||
|
||||
/* Deprecated, do not use, prefer Arch::Build */
|
||||
|
||||
const Arch *GetHostArch(llvm::LLVMContext &context) __attribute__((deprecated));
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Get the architecture of the modelled code. This is based on command-line
|
||||
// flags.
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
} // namespace remill
|
||||
@@ -14,7 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _REMILL_ARCH_ASSEMBLY_S
|
||||
#define _REMILL_ARCH_ASSEMBLY_S
|
||||
|
||||
#define CAT_3(a, b) a ## b
|
||||
#define CAT_2(a, b) CAT_3(a, b)
|
||||
@@ -43,3 +44,4 @@
|
||||
#define TO_STRING2(a) TO_STRING3(a)
|
||||
#define TO_STRING(a) TO_STRING2(a)
|
||||
|
||||
#endif // _REMILL_ARCH_ASSEMBLY_S
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef REMILL_ARCH
|
||||
# if defined(__x86_64__)
|
||||
# define REMILL_ARCH "amd64_avx"
|
||||
# define REMILL_ON_AMD64 1
|
||||
# define REMILL_ON_X86 0
|
||||
# define REMILL_ON_AARCH64 0
|
||||
# define REMILL_ON_SPARC64 0
|
||||
# define REMILL_ON_SPARC32 0
|
||||
# elif defined(__i386__) || defined(_M_X86)
|
||||
# define REMILL_ARCH "x86"
|
||||
# define REMILL_ON_AMD64 0
|
||||
# define REMILL_ON_X86 1
|
||||
# define REMILL_ON_AARCH64 0
|
||||
# define REMILL_ON_SPARC64 0
|
||||
# define REMILL_ON_SPARC32 0
|
||||
# elif defined(__aarch64__)
|
||||
# define REMILL_ARCH "aarch64"
|
||||
# define REMILL_ON_AMD64 0
|
||||
# define REMILL_ON_X86 0
|
||||
# define REMILL_ON_AARCH64 1
|
||||
# define REMILL_ON_SPARC64 0
|
||||
# define REMILL_ON_SPARC32 0
|
||||
# elif defined(__sparc__) || defined(__sparc) || defined(__sparc_v8__) || defined(__sparc_v9__) || defined(__sparcv8) || defined(__sparcv9)
|
||||
# define REMILL_ON_AMD64 0
|
||||
# define REMILL_ON_X86 0
|
||||
# define REMILL_ON_AARCH64 0
|
||||
# if (defined(__LP64__) && __LP64__) || (defined(_LP64) && _LP64)
|
||||
# define REMILL_ARCH "sparc64"
|
||||
# define REMILL_ON_SPARC64 1
|
||||
# define REMILL_ON_SPARC32 0
|
||||
# else
|
||||
# define REMILL_ARCH "sparc32"
|
||||
# define REMILL_ON_SPARC64 0
|
||||
# define REMILL_ON_SPARC32 1
|
||||
# endif
|
||||
# else
|
||||
# error "Cannot infer current architecture."
|
||||
# define REMILL_ARCH "invalid"
|
||||
# define REMILL_ON_AMD64 0
|
||||
# define REMILL_ON_X86 0
|
||||
# define REMILL_ON_AARCH64 0
|
||||
# define REMILL_ON_SPARC64 0
|
||||
# define REMILL_ON_SPARC32 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace llvm {
|
||||
class Triple;
|
||||
} // namespace llvm
|
||||
namespace remill {
|
||||
|
||||
enum ArchName : uint32_t {
|
||||
kArchInvalid,
|
||||
|
||||
kArchX86,
|
||||
kArchX86_AVX,
|
||||
kArchX86_AVX512,
|
||||
|
||||
kArchAMD64,
|
||||
kArchAMD64_AVX,
|
||||
kArchAMD64_AVX512,
|
||||
|
||||
kArchAArch64LittleEndian,
|
||||
|
||||
kArchSparc32,
|
||||
kArchSparc64,
|
||||
};
|
||||
|
||||
ArchName GetArchName(const llvm::Triple &triple);
|
||||
|
||||
// Convert the string name of an architecture into a canonical form.
|
||||
ArchName GetArchName(std::string_view arch_name);
|
||||
|
||||
std::string_view GetArchName(ArchName);
|
||||
|
||||
} // namespace remill
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cfloat>
|
||||
@@ -18,6 +34,7 @@
|
||||
#endif
|
||||
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
|
||||
// macOS does not have this flag
|
||||
#ifndef __FE_DENORM
|
||||
@@ -60,6 +60,32 @@ class SyncHyperCall {
|
||||
// TODO(pag): How to distinguish little- and big-endian?
|
||||
kAArch64EmulateInstruction = 0x200U,
|
||||
kAArch64Breakpoint,
|
||||
|
||||
kSPARC32EmulateInstruction = 0x400U,
|
||||
kSPARC64EmulateInstruction,
|
||||
kSPARCSetAsiRegister,
|
||||
kSPARCTagOverflow,
|
||||
|
||||
kSPARCUnimplementedInstruction,
|
||||
kSPARCUnhandledDCTI, // A CTI in a delay slot.
|
||||
kSPARCWindowUnderflow, // Underflow when RESTOREing a register window.
|
||||
|
||||
kSPARCTrapCondA,
|
||||
kSPARCTrapCondN,
|
||||
kSPARCTrapCondNE,
|
||||
kSPARCTrapCondE,
|
||||
kSPARCTrapCondG,
|
||||
kSPARCTrapCondLE,
|
||||
kSPARCTrapCondGE,
|
||||
kSPARCTrapCondL,
|
||||
kSPARCTrapCondGU,
|
||||
kSPARCTrapCondLEU,
|
||||
kSPARCTrapCondCC,
|
||||
kSPARCTrapCondCS,
|
||||
kSPARCTrapCondPOS,
|
||||
kSPARCTrapCondNEG,
|
||||
kSPARCTrapCondVC,
|
||||
kSPARCTrapCondVS,
|
||||
};
|
||||
} __attribute__((packed));
|
||||
|
||||
@@ -90,6 +116,28 @@ class AsyncHyperCall {
|
||||
|
||||
kAArch64SupervisorCall,
|
||||
|
||||
kSPARCTagOverflowAdd,
|
||||
kSPARCTagOverflowSub,
|
||||
|
||||
kSPARCUnimplementedInstruction,
|
||||
|
||||
kSPARCTrapCondA,
|
||||
kSPARCTrapCondN,
|
||||
kSPARCTrapCondNE,
|
||||
kSPARCTrapCondE,
|
||||
kSPARCTrapCondG,
|
||||
kSPARCTrapCondLE,
|
||||
kSPARCTrapCondGE,
|
||||
kSPARCTrapCondL,
|
||||
kSPARCTrapCondGU,
|
||||
kSPARCTrapCondLEU,
|
||||
kSPARCTrapCondCC,
|
||||
kSPARCTrapCondCS,
|
||||
kSPARCTrapCondPOS,
|
||||
kSPARCTrapCondNEG,
|
||||
kSPARCTrapCondVC,
|
||||
kSPARCTrapCondVS,
|
||||
|
||||
// Invalid instruction.
|
||||
kInvalidInstruction
|
||||
};
|
||||
@@ -19,6 +19,8 @@
|
||||
struct Memory;
|
||||
struct State;
|
||||
|
||||
#include "Float.h"
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE static uint128_t __remill_read_memory_128(Memory *mem,
|
||||
@@ -47,6 +47,9 @@ typedef int int128_t __attribute__((mode(TI)));
|
||||
#elif defined(__aarch64__)
|
||||
typedef __uint128_t uint128_t;
|
||||
typedef __int128_t int128_t;
|
||||
#elif defined(__sparc__)
|
||||
typedef __uint128_t uint128_t;
|
||||
typedef __int128_t int128_t;
|
||||
#else
|
||||
# error "Cannot determine (u)int128_t type of unuspported architecture."
|
||||
#endif
|
||||
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic fatal "-Wpadded"
|
||||
|
||||
#include "remill/Arch/Runtime/State.h"
|
||||
#include "remill/Arch/Runtime/Types.h"
|
||||
|
||||
struct Reg final {
|
||||
addr_t dword;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
union PtrReg final {
|
||||
addr_t dword;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(PtrReg) == 4);
|
||||
|
||||
struct GPR {
|
||||
// Prevents LLVM from casting a `GPR` into an `i64` to access `I0`.
|
||||
volatile addr_t _0;
|
||||
Reg i0;
|
||||
volatile addr_t _1;
|
||||
Reg i1;
|
||||
volatile addr_t _2;
|
||||
Reg i2;
|
||||
volatile addr_t _3;
|
||||
Reg i3;
|
||||
volatile addr_t _4;
|
||||
Reg i4;
|
||||
volatile addr_t _5;
|
||||
Reg i5;
|
||||
volatile addr_t _6;
|
||||
PtrReg i6;
|
||||
volatile addr_t _7;
|
||||
Reg i7;
|
||||
|
||||
volatile addr_t _8;
|
||||
Reg l0;
|
||||
volatile addr_t _9;
|
||||
Reg l1;
|
||||
volatile addr_t _10;
|
||||
Reg l2;
|
||||
volatile addr_t _11;
|
||||
Reg l3;
|
||||
volatile addr_t _12;
|
||||
Reg l4;
|
||||
volatile addr_t _13;
|
||||
Reg l5;
|
||||
volatile addr_t _14;
|
||||
Reg l6;
|
||||
volatile addr_t _15;
|
||||
Reg l7;
|
||||
|
||||
volatile addr_t _16;
|
||||
Reg o0;
|
||||
volatile addr_t _17;
|
||||
Reg o1;
|
||||
volatile addr_t _18;
|
||||
Reg o2;
|
||||
volatile addr_t _19;
|
||||
Reg o3;
|
||||
volatile addr_t _20;
|
||||
Reg o4;
|
||||
volatile addr_t _21;
|
||||
Reg o5;
|
||||
volatile addr_t _22;
|
||||
PtrReg o6;
|
||||
volatile addr_t _23;
|
||||
Reg o7;
|
||||
|
||||
volatile addr_t _24;
|
||||
Reg g0;
|
||||
volatile addr_t _25;
|
||||
Reg g1;
|
||||
volatile addr_t _26;
|
||||
Reg g2;
|
||||
volatile addr_t _27;
|
||||
Reg g3;
|
||||
volatile addr_t _28;
|
||||
Reg g4;
|
||||
volatile addr_t _29;
|
||||
Reg g5;
|
||||
volatile addr_t _30;
|
||||
Reg g6;
|
||||
volatile addr_t _31;
|
||||
Reg g7;
|
||||
};
|
||||
|
||||
enum AlternativeSpaceIdentifier : uint32_t {
|
||||
ASI_PST8_PRIMARY = 0xc0,
|
||||
ASI_PST8_SECONDARY,
|
||||
ASI_PST16_PRIMARY,
|
||||
ASI_PST16_SECONDARY,
|
||||
ASI_PST32_PRIMARY,
|
||||
ASI_PST32_SECONDARY,
|
||||
ASI_FL8_PRIMARY = 0xd0,
|
||||
ASI_FL8_SECONDARY,
|
||||
ASI_FL16_PRIMARY,
|
||||
ASI_FL16_SECONDARY,
|
||||
ASI_BLOCK_COMMIT_PRIMARY = 0xe0,
|
||||
ASI_TWINX_P = 0xe2,
|
||||
ASI_TWINX_S,
|
||||
ASI_BLOCK_PRIMARY = 0xf0,
|
||||
ASI_BLOCK_SECONDARY,
|
||||
};
|
||||
|
||||
struct alignas(8) FPURegs final {
|
||||
vec128_t v[8];
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(128 == sizeof(struct FPURegs), "Invalid packing of `struct FPURegs`.");
|
||||
|
||||
struct FSRReg final {
|
||||
volatile uint8_t _0;
|
||||
uint8_t cexc;
|
||||
volatile uint8_t _1;
|
||||
uint8_t aexc;
|
||||
volatile uint8_t _2;
|
||||
uint8_t fcc0;
|
||||
volatile uint8_t _3;
|
||||
uint8_t reserve;
|
||||
volatile uint8_t _4;
|
||||
uint8_t ftt;
|
||||
volatile uint8_t _5;
|
||||
uint8_t ver;
|
||||
volatile uint8_t _6;
|
||||
uint8_t ns;
|
||||
volatile uint8_t _7;
|
||||
uint8_t tem;
|
||||
volatile uint8_t _8;
|
||||
uint8_t rd;
|
||||
volatile uint8_t _9;
|
||||
uint8_t fcc1;
|
||||
volatile uint8_t _10;
|
||||
uint8_t fcc2;
|
||||
volatile uint8_t _11;
|
||||
uint8_t fcc3;
|
||||
}__attribute__((packed));
|
||||
|
||||
static_assert(24 == sizeof(struct FSRReg), "Invalid packing of `struct FSRReg`.");
|
||||
|
||||
// Integer condition code register flags
|
||||
struct ICCRFlags final {
|
||||
struct {
|
||||
volatile uint8_t _0;
|
||||
bool c;
|
||||
volatile uint8_t _1;
|
||||
bool v;
|
||||
volatile uint8_t _2;
|
||||
bool z;
|
||||
volatile uint8_t _3;
|
||||
bool n;
|
||||
} __attribute__((packed)) icc, xcc;
|
||||
} __attribute__((packed));
|
||||
|
||||
union GSRFlags final {
|
||||
uint64_t flat;
|
||||
struct {
|
||||
uint64_t align:3;
|
||||
uint64_t scale:5;
|
||||
uint64_t reserved_0:17;
|
||||
uint64_t irnd:2;
|
||||
uint64_t im:1;
|
||||
uint64_t reserved_1:4;
|
||||
uint64_t mask:32;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ASR final {
|
||||
Reg yreg; // ASR 0
|
||||
volatile uint32_t _0;
|
||||
ICCRFlags ccr; // ASR 2
|
||||
volatile addr_t _1;
|
||||
union {
|
||||
uint32_t asi_flat;
|
||||
struct {
|
||||
uint32_t asi:8; // ASR 3
|
||||
uint32_t padding_1:24;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
volatile uint64_t _2;
|
||||
uint64_t tick; // ASR 4
|
||||
volatile uint64_t _3;
|
||||
union {
|
||||
uint32_t fprs_flat;
|
||||
struct {
|
||||
uint32_t fprs:3; // ASR 6
|
||||
uint32_t padding_2:29;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
volatile uint32_t _4;
|
||||
GSRFlags gsr;
|
||||
volatile uint64_t _5;
|
||||
addr64_t softint; // ASR 20
|
||||
volatile uint64_t _6;
|
||||
addr64_t stick; // ASR 24
|
||||
volatile uint64_t _7;
|
||||
addr64_t stick_cmpr; // ASR 25
|
||||
volatile uint64_t _8;
|
||||
addr64_t cfr; // ASR 26
|
||||
volatile uint64_t _9;
|
||||
addr64_t pause; // ASR 27
|
||||
volatile uint64_t _10;
|
||||
addr64_t mwait; // ASR 28
|
||||
} __attribute__((packed));
|
||||
|
||||
struct CSR {
|
||||
uint8_t ccc;
|
||||
uint8_t padding0;
|
||||
uint16_t padding1;
|
||||
uint32_t padding2;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(8 == sizeof(struct CSR), "Invalid packing of `struct CSR`.");
|
||||
|
||||
struct PSR {
|
||||
uint64_t tpc;
|
||||
uint64_t tnpc;
|
||||
uint64_t tstate;
|
||||
uint64_t tick;
|
||||
uint64_t tba;
|
||||
volatile uint8_t _0; //padding
|
||||
uint8_t tt;
|
||||
uint8_t tl;
|
||||
union {
|
||||
uint16_t pstate;
|
||||
struct {
|
||||
uint16_t res1:1;
|
||||
uint16_t ie:1;
|
||||
uint16_t priv:1;
|
||||
uint16_t am:1;
|
||||
uint16_t pef:1;
|
||||
uint16_t res2:1;
|
||||
uint16_t mm:1;
|
||||
uint16_t tle:1;
|
||||
uint16_t cle:1;
|
||||
uint16_t res3:1;
|
||||
uint16_t res4:1;
|
||||
uint16_t tct:1;
|
||||
uint16_t padding:4;
|
||||
} __attribute__((packed)) ps;
|
||||
} __attribute__((packed));
|
||||
volatile uint8_t _1;
|
||||
uint8_t pil;
|
||||
uint8_t cwp;
|
||||
uint8_t cansave;
|
||||
volatile uint8_t _2;
|
||||
uint8_t canrestore;
|
||||
uint8_t cleanwin;
|
||||
uint8_t otherwin;
|
||||
volatile uint8_t _3;
|
||||
union {
|
||||
uint8_t wstate;
|
||||
struct {
|
||||
uint8_t normal:2;
|
||||
uint8_t other:3;
|
||||
uint8_t padding:3;
|
||||
} __attribute__((packed)) ws;
|
||||
} __attribute__((packed));
|
||||
uint8_t gl;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct RegisterWindow {
|
||||
volatile addr_t _0;
|
||||
addr_t l0;
|
||||
volatile addr_t _1;
|
||||
addr_t l1;
|
||||
volatile addr_t _2;
|
||||
addr_t l2;
|
||||
volatile addr_t _3;
|
||||
addr_t l3;
|
||||
volatile addr_t _4;
|
||||
addr_t l4;
|
||||
volatile addr_t _5;
|
||||
addr_t l5;
|
||||
volatile addr_t _6;
|
||||
addr_t l6;
|
||||
volatile addr_t _7;
|
||||
addr_t l7;
|
||||
|
||||
volatile addr_t _8;
|
||||
addr_t i0;
|
||||
volatile addr_t _9;
|
||||
addr_t i1;
|
||||
volatile addr_t _10;
|
||||
addr_t i2;
|
||||
volatile addr_t _11;
|
||||
addr_t i3;
|
||||
volatile addr_t _12;
|
||||
addr_t i4;
|
||||
volatile addr_t _13;
|
||||
addr_t i5;
|
||||
volatile addr_t _14;
|
||||
addr_t i6;
|
||||
volatile addr_t _15;
|
||||
addr_t i7;
|
||||
volatile addr_t _16;
|
||||
RegisterWindow *prev_window;
|
||||
};
|
||||
|
||||
struct alignas(16) State : public ArchState {
|
||||
FPURegs fpreg; // 512 bytes
|
||||
volatile uint64_t _0;
|
||||
GPR gpr; // 256 bytes
|
||||
volatile uint64_t _1;
|
||||
ASR asr; // 176 bytes
|
||||
volatile uint64_t _2;
|
||||
PSR psr; // 56 bytes
|
||||
volatile uint64_t _3;
|
||||
FSRReg fsr; // 24 bytes
|
||||
volatile uint64_t _4;
|
||||
CSR csr; // 8 bytes
|
||||
volatile uint32_t _5;
|
||||
Reg pc; // 4 bytes
|
||||
volatile uint32_t _6;
|
||||
Reg next_pc; // 4 bytes
|
||||
volatile uint32_t _7;
|
||||
|
||||
// NOTE(pag): This *must* go at the end, as if we change the target arch/data
|
||||
// layout, then we want to make sure that the offset of this
|
||||
// remains the same and doesn't shift other things around.
|
||||
#if defined(INCLUDED_FROM_REMILL)
|
||||
uint32_t window;
|
||||
#else
|
||||
RegisterWindow *window; // smuggled.
|
||||
static_assert(sizeof(RegisterWindow *) == 4, "Invalid size of `RegisterWindow`");
|
||||
#endif
|
||||
};
|
||||
|
||||
using SPARCState = State;
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef RnW<uint8_t> R8W;
|
||||
typedef RnW<uint16_t> R16W;
|
||||
typedef RnW<uint32_t> R32W;
|
||||
typedef RnW<uint64_t> R64W;
|
||||
|
||||
typedef Rn<uint8_t> R8;
|
||||
typedef Rn<uint16_t> R16;
|
||||
typedef Rn<uint32_t> R32;
|
||||
typedef Rn<uint64_t> R64;
|
||||
|
||||
typedef Mn<uint8_t> M8;
|
||||
typedef Mn<uint16_t> M16;
|
||||
typedef Mn<uint32_t> M32;
|
||||
typedef Mn<uint64_t> M64;
|
||||
|
||||
typedef MnW<uint8_t> M8W;
|
||||
typedef MnW<uint16_t> M16W;
|
||||
typedef MnW<uint32_t> M32W;
|
||||
typedef MnW<uint64_t> M64W;
|
||||
|
||||
typedef MVn<vec8_t> MV8;
|
||||
typedef MVn<vec16_t> MV16;
|
||||
typedef MVn<vec32_t> MV32;
|
||||
typedef MVn<vec64_t> MV64;
|
||||
|
||||
typedef MVnW<vec8_t> MV8W;
|
||||
typedef MVnW<vec16_t> MV16W;
|
||||
typedef MVnW<vec32_t> MV32W;
|
||||
typedef MVnW<vec64_t> MV64W;
|
||||
typedef MVnW<vec128_t> MV128W;
|
||||
|
||||
typedef In<uint8_t> I8;
|
||||
typedef In<uint16_t> I16;
|
||||
typedef In<uint32_t> I32;
|
||||
typedef In<uint64_t> I64;
|
||||
|
||||
typedef RnW<addr_t> Rr;
|
||||
typedef RnW<float32_t> Fs;
|
||||
typedef RnW<float64_t> Fd;
|
||||
|
||||
typedef Rn<float32_t> RF32;
|
||||
typedef Rn<float64_t> RF64;
|
||||
|
||||
typedef RnW<float32_t> RF32W;
|
||||
typedef RnW<float64_t> RF64W;
|
||||
|
||||
typedef MnW<float32_t> MF32W;
|
||||
typedef MnW<float64_t> MF64W;
|
||||
|
||||
|
||||
// NOTE(pag): This is a bit of a lie; we use `double`s to represent 128-bit
|
||||
// floats from SPARC.
|
||||
typedef RnW<float64_t> Fq;
|
||||
|
||||
typedef Vn<vec8_t> V8;
|
||||
typedef Vn<vec16_t> V16;
|
||||
typedef RVn<vec32_t> V32;
|
||||
typedef RVn<vec64_t> V64;
|
||||
typedef Vn<vec128_t> V128;
|
||||
|
||||
typedef VnW<vec8_t> V8W;
|
||||
typedef RVnW<vec32_t> V32W;
|
||||
typedef RVnW<vec64_t> V64W;
|
||||
typedef VnW<vec128_t> V128W;
|
||||
|
||||
typedef MnW<float32_t> MF32W;
|
||||
typedef MnW<float64_t> MF64W;
|
||||
|
||||
typedef In<float32_t> F32;
|
||||
typedef In<float64_t> F64;
|
||||
|
||||
typedef In<addr_t> PC;
|
||||
typedef In<addr_t> IMM;
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic fatal "-Wpadded"
|
||||
|
||||
#include "remill/Arch/Runtime/State.h"
|
||||
#include "remill/Arch/Runtime/Types.h"
|
||||
|
||||
struct Reg final {
|
||||
addr_t qword;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(Reg) == 8,
|
||||
"Invalid size of `Reg`.");
|
||||
|
||||
union PtrReg final {
|
||||
addr_t qword;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(PtrReg) == 8,
|
||||
"Invalid size of `PtrReg`.");
|
||||
|
||||
struct GPR {
|
||||
// Prevents LLVM from casting a `GPR` into an `i64` to access `I0`.
|
||||
volatile addr_t _0;
|
||||
Reg i0;
|
||||
volatile addr_t _1;
|
||||
Reg i1;
|
||||
volatile addr_t _2;
|
||||
Reg i2;
|
||||
volatile addr_t _3;
|
||||
Reg i3;
|
||||
volatile addr_t _4;
|
||||
Reg i4;
|
||||
volatile addr_t _5;
|
||||
Reg i5;
|
||||
volatile addr_t _6;
|
||||
Reg i6;
|
||||
volatile addr_t _7;
|
||||
Reg i7;
|
||||
|
||||
volatile addr_t _8;
|
||||
Reg l0;
|
||||
volatile addr_t _9;
|
||||
Reg l1;
|
||||
volatile addr_t _10;
|
||||
Reg l2;
|
||||
volatile addr_t _11;
|
||||
Reg l3;
|
||||
volatile addr_t _12;
|
||||
Reg l4;
|
||||
volatile addr_t _13;
|
||||
Reg l5;
|
||||
volatile addr_t _14;
|
||||
Reg l6;
|
||||
volatile addr_t _15;
|
||||
Reg l7;
|
||||
|
||||
volatile addr_t _16;
|
||||
Reg o0;
|
||||
volatile addr_t _17;
|
||||
Reg o1;
|
||||
volatile addr_t _18;
|
||||
Reg o2;
|
||||
volatile addr_t _19;
|
||||
Reg o3;
|
||||
volatile addr_t _20;
|
||||
Reg o4;
|
||||
volatile addr_t _21;
|
||||
Reg o5;
|
||||
volatile addr_t _22;
|
||||
Reg o6;
|
||||
volatile addr_t _23;
|
||||
Reg o7;
|
||||
|
||||
volatile addr_t _24;
|
||||
Reg g0;
|
||||
volatile addr_t _25;
|
||||
Reg g1;
|
||||
volatile addr_t _26;
|
||||
Reg g2;
|
||||
volatile addr_t _27;
|
||||
Reg g3;
|
||||
volatile addr_t _28;
|
||||
Reg g4;
|
||||
volatile addr_t _29;
|
||||
Reg g5;
|
||||
volatile addr_t _30;
|
||||
Reg g6;
|
||||
volatile addr_t _31;
|
||||
Reg g7;
|
||||
};
|
||||
|
||||
static_assert(512 == sizeof(GPR),
|
||||
"Invalid packing of `struct GPR`.");
|
||||
|
||||
enum AlternativeSpaceIdentifier : uint32_t {
|
||||
ASI_PST8_PRIMARY = 0xc0,
|
||||
ASI_PST8_SECONDARY,
|
||||
ASI_PST16_PRIMARY,
|
||||
ASI_PST16_SECONDARY,
|
||||
ASI_PST32_PRIMARY,
|
||||
ASI_PST32_SECONDARY,
|
||||
ASI_FL8_PRIMARY = 0xd0,
|
||||
ASI_FL8_SECONDARY,
|
||||
ASI_FL16_PRIMARY,
|
||||
ASI_FL16_SECONDARY,
|
||||
ASI_BLOCK_COMMIT_PRIMARY = 0xe0,
|
||||
ASI_TWINX_P = 0xe2,
|
||||
ASI_TWINX_S,
|
||||
ASI_BLOCK_PRIMARY = 0xf0,
|
||||
ASI_BLOCK_SECONDARY,
|
||||
};
|
||||
|
||||
struct FPURegs final {
|
||||
vec128_t v[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(((128 * 16) / 8) == sizeof(struct FPURegs), "Invalid packing of `struct FPURegs`.");
|
||||
|
||||
struct FSRReg final {
|
||||
volatile uint8_t _0;
|
||||
uint8_t cexc;
|
||||
volatile uint8_t _1;
|
||||
uint8_t aexc;
|
||||
volatile uint8_t _2;
|
||||
uint8_t fcc0;
|
||||
volatile uint8_t _3;
|
||||
uint8_t reserve;
|
||||
volatile uint8_t _4;
|
||||
uint8_t ftt;
|
||||
volatile uint8_t _5;
|
||||
uint8_t ver;
|
||||
volatile uint8_t _6;
|
||||
uint8_t ns;
|
||||
volatile uint8_t _7;
|
||||
uint8_t tem;
|
||||
volatile uint8_t _8;
|
||||
uint8_t rd;
|
||||
volatile uint8_t _9;
|
||||
uint8_t fcc1;
|
||||
volatile uint8_t _10;
|
||||
uint8_t fcc2;
|
||||
volatile uint8_t _11;
|
||||
uint8_t fcc3;
|
||||
}__attribute__((packed));
|
||||
|
||||
static_assert(24 == sizeof(struct FSRReg), "Invalid packing of `struct FSRReg`.");
|
||||
|
||||
// Integer condition code register flags
|
||||
struct ICCRFlags final {
|
||||
struct {
|
||||
volatile uint8_t _0;
|
||||
bool c;
|
||||
volatile uint8_t _1;
|
||||
bool v;
|
||||
volatile uint8_t _2;
|
||||
bool z;
|
||||
volatile uint8_t _3;
|
||||
bool n;
|
||||
} __attribute__((packed)) icc, xcc;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(16 == sizeof(struct ICCRFlags), "Invalid packing of `struct ICCRFlags`.");
|
||||
|
||||
union GSRFlags final {
|
||||
uint64_t flat;
|
||||
struct {
|
||||
uint64_t align:3;
|
||||
uint64_t scale:5;
|
||||
uint64_t reserved_0:17;
|
||||
uint64_t irnd:2;
|
||||
uint64_t im:1;
|
||||
uint64_t reserved_1:4;
|
||||
uint64_t mask:32;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ASR final {
|
||||
Reg yreg; // ASR 0
|
||||
volatile uint64_t _0;
|
||||
ICCRFlags ccr; // ASR 2
|
||||
volatile uint64_t _1;
|
||||
union {
|
||||
uint64_t asi_flat;
|
||||
struct {
|
||||
uint64_t asi:8; // ASR 3
|
||||
uint64_t padding_1:56;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
volatile uint64_t _2;
|
||||
uint64_t tick; // ASR 4
|
||||
volatile uint64_t _3;
|
||||
union {
|
||||
uint64_t fprs_flat;
|
||||
struct {
|
||||
uint64_t fprs:3; // ASR 6
|
||||
uint64_t padding_2:61;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
volatile uint64_t _4;
|
||||
GSRFlags gsr;
|
||||
volatile uint64_t _5;
|
||||
uint64_t softint; // ASR 20
|
||||
volatile uint64_t _6;
|
||||
uint64_t stick; // ASR 24
|
||||
volatile uint64_t _7;
|
||||
uint64_t stick_cmpr; // ASR 25
|
||||
volatile uint64_t _8;
|
||||
uint64_t cfr; // ASR 26
|
||||
volatile uint64_t _9;
|
||||
uint64_t pause; // ASR 27
|
||||
volatile uint64_t _10;
|
||||
uint64_t mwait; // ASR 28
|
||||
};
|
||||
|
||||
static_assert(192 == sizeof(struct ASR), "Invalid packing of `struct ASR`.");
|
||||
|
||||
struct CSR {
|
||||
uint8_t ccc;
|
||||
uint8_t padding0;
|
||||
uint16_t padding1;
|
||||
uint32_t padding2;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(8 == sizeof(struct CSR), "Invalid packing of `struct CSR`.");
|
||||
|
||||
struct PSR {
|
||||
uint64_t tpc;
|
||||
uint64_t tnpc;
|
||||
uint64_t tstate;
|
||||
uint64_t tick;
|
||||
uint64_t tba;
|
||||
volatile uint8_t _0; //padding
|
||||
uint8_t tt;
|
||||
uint8_t tl;
|
||||
union {
|
||||
uint16_t pstate;
|
||||
struct {
|
||||
uint16_t res1:1;
|
||||
uint16_t ie:1;
|
||||
uint16_t priv:1;
|
||||
uint16_t am:1;
|
||||
uint16_t pef:1;
|
||||
uint16_t res2:1;
|
||||
uint16_t mm:1;
|
||||
uint16_t tle:1;
|
||||
uint16_t cle:1;
|
||||
uint16_t res3:1;
|
||||
uint16_t res4:1;
|
||||
uint16_t tct:1;
|
||||
uint16_t padding:4;
|
||||
} __attribute__((packed)) ps;
|
||||
} __attribute__((packed));
|
||||
volatile uint8_t _1;
|
||||
uint8_t pil;
|
||||
uint8_t cwp;
|
||||
uint8_t cansave;
|
||||
volatile uint8_t _2;
|
||||
uint8_t canrestore;
|
||||
uint8_t cleanwin;
|
||||
uint8_t otherwin;
|
||||
volatile uint8_t _3;
|
||||
union {
|
||||
uint8_t wstate;
|
||||
struct {
|
||||
uint8_t normal:2;
|
||||
uint8_t other:3;
|
||||
uint8_t padding:3;
|
||||
} __attribute__((packed)) ws;
|
||||
} __attribute__((packed));
|
||||
uint8_t gl;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct RegisterWindow {
|
||||
volatile addr_t _0;
|
||||
addr_t l0;
|
||||
volatile addr_t _1;
|
||||
addr_t l1;
|
||||
volatile addr_t _2;
|
||||
addr_t l2;
|
||||
volatile addr_t _3;
|
||||
addr_t l3;
|
||||
volatile addr_t _4;
|
||||
addr_t l4;
|
||||
volatile addr_t _5;
|
||||
addr_t l5;
|
||||
volatile addr_t _6;
|
||||
addr_t l6;
|
||||
volatile addr_t _7;
|
||||
addr_t l7;
|
||||
|
||||
volatile addr_t _8;
|
||||
addr_t i0;
|
||||
volatile addr_t _9;
|
||||
addr_t i1;
|
||||
volatile addr_t _10;
|
||||
addr_t i2;
|
||||
volatile addr_t _11;
|
||||
addr_t i3;
|
||||
volatile addr_t _12;
|
||||
addr_t i4;
|
||||
volatile addr_t _13;
|
||||
addr_t i5;
|
||||
volatile addr_t _14;
|
||||
addr_t i6;
|
||||
volatile addr_t _15;
|
||||
addr_t i7;
|
||||
|
||||
volatile addr_t _16;
|
||||
RegisterWindow *prev_window;
|
||||
};
|
||||
|
||||
struct alignas(16) State : public ArchState {
|
||||
FPURegs fpreg; // 512 bytes
|
||||
volatile uint64_t _0;
|
||||
GPR gpr; // 512 bytes
|
||||
volatile uint64_t _1;
|
||||
ASR asr; // 176 bytes
|
||||
volatile uint64_t _2;
|
||||
PSR psr; // 56 bytes
|
||||
volatile uint64_t _3;
|
||||
FSRReg fsr; // 24 bytes
|
||||
volatile uint64_t _4;
|
||||
CSR csr; // 8 bytes
|
||||
volatile uint64_t _5;
|
||||
Reg pc; // 8 bytes
|
||||
volatile uint64_t _6;
|
||||
Reg next_pc; // 8 bytes
|
||||
volatile uint64_t _7;
|
||||
|
||||
// NOTE(pag): This *must* go at the end, as if we change the target arch/data
|
||||
// layout, then we want to make sure that the offset of this
|
||||
// remains the same and doesn't shift other things around.
|
||||
#if defined(INCLUDED_FROM_REMILL)
|
||||
uint64_t window;
|
||||
#else
|
||||
RegisterWindow *window; // smuggled.
|
||||
static_assert(sizeof(RegisterWindow *) == 8, "Invalid size of `RegisterWindow`");
|
||||
#endif
|
||||
};
|
||||
|
||||
using SPARCState = State;
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
typedef RnW<uint8_t> R8W;
|
||||
typedef RnW<uint16_t> R16W;
|
||||
typedef RnW<uint32_t> R32W;
|
||||
typedef RnW<uint64_t> R64W;
|
||||
|
||||
typedef Rn<uint8_t> R8;
|
||||
typedef Rn<uint16_t> R16;
|
||||
typedef Rn<uint32_t> R32;
|
||||
typedef Rn<uint64_t> R64;
|
||||
|
||||
typedef Mn<uint8_t> M8;
|
||||
typedef Mn<uint16_t> M16;
|
||||
typedef Mn<uint32_t> M32;
|
||||
typedef Mn<uint64_t> M64;
|
||||
|
||||
typedef MnW<uint8_t> M8W;
|
||||
typedef MnW<uint16_t> M16W;
|
||||
typedef MnW<uint32_t> M32W;
|
||||
typedef MnW<uint64_t> M64W;
|
||||
|
||||
typedef MVn<vec8_t> MV8;
|
||||
typedef MVn<vec16_t> MV16;
|
||||
typedef MVn<vec32_t> MV32;
|
||||
typedef MVn<vec64_t> MV64;
|
||||
|
||||
typedef MVnW<vec8_t> MV8W;
|
||||
typedef MVnW<vec16_t> MV16W;
|
||||
typedef MVnW<vec32_t> MV32W;
|
||||
typedef MVnW<vec64_t> MV64W;
|
||||
typedef MVnW<vec128_t> MV128W;
|
||||
|
||||
typedef In<uint8_t> I8;
|
||||
typedef In<uint16_t> I16;
|
||||
typedef In<uint32_t> I32;
|
||||
typedef In<uint64_t> I64;
|
||||
|
||||
typedef RnW<addr_t> Rr;
|
||||
typedef RnW<float32_t> Fs;
|
||||
typedef RnW<float64_t> Fd;
|
||||
|
||||
typedef Rn<float32_t> RF32;
|
||||
typedef Rn<float64_t> RF64;
|
||||
|
||||
typedef RnW<float32_t> RF32W;
|
||||
typedef RnW<float64_t> RF64W;
|
||||
|
||||
typedef MnW<float32_t> MF32W;
|
||||
typedef MnW<float64_t> MF64W;
|
||||
|
||||
|
||||
// NOTE(pag): This is a bit of a lie; we use `double`s to represent 128-bit
|
||||
// floats from SPARC.
|
||||
typedef RnW<float64_t> Fq;
|
||||
|
||||
typedef Vn<vec8_t> V8;
|
||||
typedef Vn<vec16_t> V16;
|
||||
typedef RVn<vec32_t> V32;
|
||||
typedef RVn<vec64_t> V64;
|
||||
typedef Vn<vec128_t> V128;
|
||||
|
||||
typedef VnW<vec8_t> V8W;
|
||||
typedef RVnW<vec32_t> V32W;
|
||||
typedef RVnW<vec64_t> V64W;
|
||||
typedef VnW<vec128_t> V128W;
|
||||
|
||||
typedef MnW<float32_t> MF32W;
|
||||
typedef MnW<float64_t> MF64W;
|
||||
|
||||
typedef In<float32_t> F32;
|
||||
typedef In<float64_t> F64;
|
||||
|
||||
typedef In<addr_t> PC;
|
||||
typedef In<addr_t> IMM;
|
||||
@@ -73,6 +73,11 @@ enum TableIndicator : uint16_t {
|
||||
kLocalDescriptorTable = 1
|
||||
};
|
||||
|
||||
#ifndef __clang__
|
||||
# define RequestPrivilegeLevel uint16_t
|
||||
# define TableIndicator uint16_t
|
||||
#endif
|
||||
|
||||
union SegmentSelector final {
|
||||
uint16_t flat;
|
||||
struct {
|
||||
@@ -136,6 +141,12 @@ enum FPURoundingControl : uint16_t {
|
||||
|
||||
enum FPUInfinityControl : uint16_t { kInfinityProjective, kInfinityAffine };
|
||||
|
||||
#ifndef __clang__
|
||||
# define FPUPrecisionControl uint16_t
|
||||
# define FPURoundingControl uint16_t
|
||||
# define FPUInfinityControl uint16_t
|
||||
#endif
|
||||
|
||||
union FPUControlWord final {
|
||||
uint16_t flat;
|
||||
struct {
|
||||
@@ -217,6 +228,11 @@ enum FPUTag : uint16_t {
|
||||
|
||||
enum FPUAbridgedTag : uint8_t { kFPUAbridgedTagEmpty, kFPUAbridgedTagValid };
|
||||
|
||||
#ifndef __clang__
|
||||
# define FPUTag uint16_t
|
||||
# define FPUAbridgedTag uint8_t
|
||||
#endif
|
||||
|
||||
// Note: Stored in top-of-stack order.
|
||||
union FPUTagWord final {
|
||||
uint16_t flat;
|
||||
@@ -526,6 +542,17 @@ enum CodeSegmentMode : uint64_t {
|
||||
|
||||
enum SegmentSystemBit : uint64_t { kSegmentBitSystem, kSegmentBitUser };
|
||||
|
||||
#ifndef __clang__
|
||||
# define DescriptorPrivilegeLevel uint64_t
|
||||
# define DescriptorClass uint64_t
|
||||
# define SegmentGranularity uint64_t
|
||||
# define SegmentDefaultOperandSize uint64_t
|
||||
# define SegmentPresentStatus uint64_t
|
||||
# define SystemDescriptorType uint64_t
|
||||
# define CodeSegmentMode uint64_t
|
||||
# define SegmentSystemBit uint64_t
|
||||
#endif
|
||||
|
||||
struct GenericDescriptor {
|
||||
uint64_t unused : 44;
|
||||
uint64_t sbit : 1;
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
} // namespace llvm
|
||||
namespace remill {
|
||||
|
||||
// Describes the arguments to a basic block function.
|
||||
enum : size_t {
|
||||
kStatePointerArgNum = 0,
|
||||
kPCArgNum = 1,
|
||||
kMemoryPointerArgNum = 2,
|
||||
kNumBlockArgs = 3
|
||||
};
|
||||
|
||||
extern const std::string_view kMemoryVariableName;
|
||||
extern const std::string_view kStateVariableName;
|
||||
extern const std::string_view kPCVariableName;
|
||||
extern const std::string_view kNextPCVariableName;
|
||||
extern const std::string_view kReturnPCVariableName;
|
||||
extern const std::string_view kBranchTakenVariableName;
|
||||
|
||||
extern const std::string_view kInvalidInstructionISelName;
|
||||
extern const std::string_view kUnsupportedInstructionISelName;
|
||||
|
||||
} // namespace remill
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
#include "Version.h"
|
||||
|
||||
namespace remill {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Trail of Bits, Inc.
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include <llvm/IR/Instructions.h>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
// Hack in a 'FixedVectorType' for LLVM < 11
|
||||
namespace llvm {
|
||||
#if LLVM_VERSION_NUMBER < LLVM_VERSION(11, 0)
|
||||
@@ -25,7 +27,7 @@ using FixedVectorType = VectorType;
|
||||
#endif
|
||||
|
||||
|
||||
constexpr auto GetFixedVectorTypeId() {
|
||||
inline static constexpr auto GetFixedVectorTypeId(void) {
|
||||
#if LLVM_VERSION_NUMBER < LLVM_VERSION(11, 0)
|
||||
return Type::VectorTyID;
|
||||
#else
|
||||
@@ -17,10 +17,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
|
||||
namespace llvm {
|
||||
class Argument;
|
||||
@@ -75,21 +73,13 @@ class InstructionLifter {
|
||||
LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block,
|
||||
bool is_delayed = false);
|
||||
|
||||
const Arch *const arch;
|
||||
|
||||
// Machine word type for this architecture.
|
||||
llvm::IntegerType *const word_type;
|
||||
|
||||
// Set of intrinsics.
|
||||
const IntrinsicTable *const intrinsics;
|
||||
|
||||
// Load the address of a register.
|
||||
llvm::Value *LoadRegAddress(llvm::BasicBlock *block, llvm::Value *state_ptr,
|
||||
const std::string ®_name);
|
||||
std::string_view reg_name);
|
||||
|
||||
// Load the value of a register.
|
||||
llvm::Value *LoadRegValue(llvm::BasicBlock *block, llvm::Value *state_ptr,
|
||||
const std::string ®_name);
|
||||
std::string_view reg_name);
|
||||
|
||||
protected:
|
||||
friend class TraceLifter;
|
||||
@@ -124,100 +114,16 @@ class InstructionLifter {
|
||||
// Return a register value, or zero.
|
||||
llvm::Value *
|
||||
LoadWordRegValOrZero(llvm::BasicBlock *block, llvm::Value *state_ptr,
|
||||
const std::string ®_name, llvm::ConstantInt *zero);
|
||||
|
||||
std::unordered_map<std::string, llvm::Value *> reg_ptr_cache;
|
||||
std::string_view reg_name, llvm::ConstantInt *zero);
|
||||
|
||||
private:
|
||||
InstructionLifter(const InstructionLifter &) = delete;
|
||||
InstructionLifter(InstructionLifter &&) noexcept = delete;
|
||||
InstructionLifter(void) = delete;
|
||||
|
||||
llvm::Function *last_func;
|
||||
};
|
||||
|
||||
using TraceMap = std::unordered_map<uint64_t, llvm::Function *>;
|
||||
|
||||
enum class DevirtualizedTargetKind { kTraceLocal, kTraceHead };
|
||||
|
||||
// Manages information about traces. Permits a user of the trace lifter to
|
||||
// provide more global information to the decoder as it goes, e.g. by pre-
|
||||
// declaring the existence of many traces, and by supporting devirtualization.
|
||||
class TraceManager {
|
||||
public:
|
||||
virtual ~TraceManager(void);
|
||||
|
||||
// Figure out the name for the trace starting at address `addr`.
|
||||
//
|
||||
// By default, the naming scheme is `sub_XXX` where `XXX` is the lower case
|
||||
// hexadecimal representation of `addr`.
|
||||
virtual std::string TraceName(uint64_t addr);
|
||||
|
||||
// Called when we have lifted, i.e. defined the contents, of a new trace.
|
||||
// The derived class is expected to do something useful with this.
|
||||
virtual void SetLiftedTraceDefinition(uint64_t addr,
|
||||
llvm::Function *lifted_func) = 0;
|
||||
|
||||
// Get a declaration for a lifted trace. The idea here is that a derived
|
||||
// class might have additional global info available to them that lets
|
||||
// them declare traces ahead of time. In order to distinguish between
|
||||
// stuff we've lifted, and stuff we haven't lifted, we allow the lifter
|
||||
// to access "defined" vs. "declared" traces.
|
||||
//
|
||||
// NOTE: This is permitted to return a function from an arbitrary module.
|
||||
//
|
||||
// NOTE: This must return a function with our special 3-argument
|
||||
// lifted function form.
|
||||
virtual llvm::Function *GetLiftedTraceDeclaration(uint64_t addr);
|
||||
|
||||
// Get a definition for a lifted trace.
|
||||
//
|
||||
// NOTE: This is permitted to return a function from an arbitrary module.
|
||||
//
|
||||
// NOTE: This is permitted to return a function of an arbitrary
|
||||
// type. The trace lifter only invokes this function when
|
||||
// it is checking if some trace has already been lifted.
|
||||
virtual llvm::Function *GetLiftedTraceDefinition(uint64_t addr);
|
||||
|
||||
// Apply a callback that gives the decoder access to multiple
|
||||
// targets of this instruction (indirect call or jump). This enables the
|
||||
// lifter to support devirtualization, e.g. handling jump tables as
|
||||
// `switch` statements, or handling indirect calls through the PLT as
|
||||
// direct jumps.
|
||||
virtual void ForEachDevirtualizedTarget(
|
||||
const Instruction &inst,
|
||||
std::function<void(uint64_t, DevirtualizedTargetKind)> func);
|
||||
|
||||
// Try to read an executable byte of memory. Returns `true` of the byte
|
||||
// at address `addr` is executable and readable, and updates the byte
|
||||
// pointed to by `byte` with the read value.
|
||||
virtual bool TryReadExecutableByte(uint64_t addr, uint8_t *byte) = 0;
|
||||
};
|
||||
|
||||
// Implements a recursive decoder that lifts a trace of instructions to bitcode.
|
||||
class TraceLifter {
|
||||
public:
|
||||
~TraceLifter(void);
|
||||
|
||||
inline TraceLifter(InstructionLifter &inst_lifter_, TraceManager &manager_)
|
||||
: TraceLifter(&inst_lifter_, &manager_) {}
|
||||
|
||||
TraceLifter(InstructionLifter *inst_lifter_, TraceManager *manager_);
|
||||
|
||||
static void NullCallback(uint64_t, llvm::Function *);
|
||||
|
||||
// Lift one or more traces starting from `addr`. Calls `callback` with each
|
||||
// lifted trace.
|
||||
bool
|
||||
Lift(uint64_t addr,
|
||||
std::function<void(uint64_t, llvm::Function *)> callback = NullCallback);
|
||||
|
||||
private:
|
||||
TraceLifter(void) = delete;
|
||||
|
||||
class Impl;
|
||||
|
||||
std::unique_ptr<Impl> impl;
|
||||
const std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace remill
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 202 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "InstructionLifter.h"
|
||||
#include "TraceLifter.h"
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <remill/BC/Lifter.h>
|
||||
|
||||
namespace remill {
|
||||
|
||||
using TraceMap = std::unordered_map<uint64_t, llvm::Function *>;
|
||||
|
||||
enum class DevirtualizedTargetKind { kTraceLocal, kTraceHead };
|
||||
|
||||
// Manages information about traces. Permits a user of the trace lifter to
|
||||
// provide more global information to the decoder as it goes, e.g. by pre-
|
||||
// declaring the existence of many traces, and by supporting devirtualization.
|
||||
class TraceManager {
|
||||
public:
|
||||
virtual ~TraceManager(void);
|
||||
|
||||
// Figure out the name for the trace starting at address `addr`.
|
||||
//
|
||||
// By default, the naming scheme is `sub_XXX` where `XXX` is the lower case
|
||||
// hexadecimal representation of `addr`.
|
||||
virtual std::string TraceName(uint64_t addr);
|
||||
|
||||
// Called when we have lifted, i.e. defined the contents, of a new trace.
|
||||
// The derived class is expected to do something useful with this.
|
||||
virtual void SetLiftedTraceDefinition(uint64_t addr,
|
||||
llvm::Function *lifted_func) = 0;
|
||||
|
||||
// Get a declaration for a lifted trace. The idea here is that a derived
|
||||
// class might have additional global info available to them that lets
|
||||
// them declare traces ahead of time. In order to distinguish between
|
||||
// stuff we've lifted, and stuff we haven't lifted, we allow the lifter
|
||||
// to access "defined" vs. "declared" traces.
|
||||
//
|
||||
// NOTE: This is permitted to return a function from an arbitrary module.
|
||||
//
|
||||
// NOTE: This must return a function with our special 3-argument
|
||||
// lifted function form.
|
||||
virtual llvm::Function *GetLiftedTraceDeclaration(uint64_t addr);
|
||||
|
||||
// Get a definition for a lifted trace.
|
||||
//
|
||||
// NOTE: This is permitted to return a function from an arbitrary module.
|
||||
//
|
||||
// NOTE: This is permitted to return a function of an arbitrary
|
||||
// type. The trace lifter only invokes this function when
|
||||
// it is checking if some trace has already been lifted.
|
||||
virtual llvm::Function *GetLiftedTraceDefinition(uint64_t addr);
|
||||
|
||||
// Apply a callback that gives the decoder access to multiple
|
||||
// targets of this instruction (indirect call or jump). This enables the
|
||||
// lifter to support devirtualization, e.g. handling jump tables as
|
||||
// `switch` statements, or handling indirect calls through the PLT as
|
||||
// direct jumps.
|
||||
virtual void ForEachDevirtualizedTarget(
|
||||
const Instruction &inst,
|
||||
std::function<void(uint64_t, DevirtualizedTargetKind)> func);
|
||||
|
||||
// Try to read an executable byte of memory. Returns `true` of the byte
|
||||
// at address `addr` is executable and readable, and updates the byte
|
||||
// pointed to by `byte` with the read value.
|
||||
virtual bool TryReadExecutableByte(uint64_t addr, uint8_t *byte) = 0;
|
||||
};
|
||||
|
||||
// Implements a recursive decoder that lifts a trace of instructions to bitcode.
|
||||
class TraceLifter {
|
||||
public:
|
||||
~TraceLifter(void);
|
||||
|
||||
inline TraceLifter(InstructionLifter &inst_lifter_, TraceManager &manager_)
|
||||
: TraceLifter(&inst_lifter_, &manager_) {}
|
||||
|
||||
TraceLifter(InstructionLifter *inst_lifter_, TraceManager *manager_);
|
||||
|
||||
static void NullCallback(uint64_t, llvm::Function *);
|
||||
|
||||
// Lift one or more traces starting from `addr`. Calls `callback` with each
|
||||
// lifted trace.
|
||||
bool
|
||||
Lift(uint64_t addr,
|
||||
std::function<void(uint64_t, llvm::Function *)> callback = NullCallback);
|
||||
|
||||
private:
|
||||
TraceLifter(void) = delete;
|
||||
|
||||
class Impl;
|
||||
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace remill
|
||||
@@ -69,12 +69,12 @@ llvm::CallInst *AddTerminatingTailCall(llvm::BasicBlock *source_block,
|
||||
|
||||
// Find a local variable defined in the entry block of the function. We use
|
||||
// this to find register variables.
|
||||
llvm::Value *FindVarInFunction(llvm::BasicBlock *block, const std::string &name,
|
||||
llvm::Value *FindVarInFunction(llvm::BasicBlock *block, std::string_view name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Find a local variable defined in the entry block of the function. We use
|
||||
// this to find register variables.
|
||||
llvm::Value *FindVarInFunction(llvm::Function *func, const std::string &name,
|
||||
llvm::Value *FindVarInFunction(llvm::Function *func, std::string_view name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Find the machine state pointer. The machine state pointer is, by convention,
|
||||
@@ -125,30 +125,20 @@ llvm::Value *LoadBranchTaken(llvm::BasicBlock *block);
|
||||
llvm::Value *LoadBranchTakenRef(llvm::BasicBlock *block);
|
||||
|
||||
// Find a function with name `name` in the module `M`.
|
||||
llvm::Function *FindFunction(llvm::Module *M, const std::string &name);
|
||||
llvm::Function *FindFunction(llvm::Module *M, std::string_view name);
|
||||
|
||||
// Find a global variable with name `name` in the module `M`.
|
||||
llvm::GlobalVariable *FindGlobaVariable(llvm::Module *M,
|
||||
const std::string &name);
|
||||
std::string_view name);
|
||||
|
||||
// Try to verify a module.
|
||||
bool VerifyModule(llvm::Module *module);
|
||||
|
||||
// Parses and loads a bitcode file into memory.
|
||||
std::unique_ptr<llvm::Module> LoadModuleFromFile(llvm::LLVMContext *context,
|
||||
const std::string &file_name,
|
||||
std::string_view file_name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Loads the semantics for the "host" machine, i.e. the machine that this
|
||||
// remill is compiled on.
|
||||
std::unique_ptr<llvm::Module> LoadHostSemantics(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Loads the semantics for the "target" machine, i.e. the machine of the
|
||||
// code that we want to lift.
|
||||
std::unique_ptr<llvm::Module> LoadTargetSemantics(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Loads the semantics for the `arch`-specific machine, i.e. the machine of the
|
||||
// code that we want to lift.
|
||||
std::unique_ptr<llvm::Module> LoadArchSemantics(const Arch *arch);
|
||||
@@ -159,22 +149,22 @@ LoadArchSemantics(const std::unique_ptr<const Arch> &arch) {
|
||||
}
|
||||
|
||||
// Store an LLVM module into a file.
|
||||
bool StoreModuleToFile(llvm::Module *module, const std::string &file_name,
|
||||
bool StoreModuleToFile(llvm::Module *module, std::string_view file_name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Store a module, serialized to LLVM IR, into a file.
|
||||
bool StoreModuleIRToFile(llvm::Module *module, const std::string &file_name,
|
||||
bool StoreModuleIRToFile(llvm::Module *module, std::string_view file_name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Find the path to the semantics bitcode file associated with `FLAGS_arch`.
|
||||
std::string FindTargetSemanticsBitcodeFile(void);
|
||||
std::string FindTargetSemanticsBitcodeFile(void) __attribute__((deprecated));
|
||||
|
||||
// Find the path to the semantics bitcode file associated with `REMILL_ARCH`,
|
||||
// the architecture on which remill is compiled.
|
||||
std::string FindHostSemanticsBitcodeFile(void);
|
||||
std::string FindHostSemanticsBitcodeFile(void) __attribute__((deprecated));
|
||||
|
||||
// Find a semantics fitcode file for the architecture `arch`.
|
||||
std::string FindSemanticsBitcodeFile(const std::string &arch);
|
||||
// Find a semantics bitcode file for the architecture `arch`.
|
||||
std::string FindSemanticsBitcodeFile(std::string_view arch);
|
||||
|
||||
// Return a pointer to the Nth argument (N=0 is the first argument).
|
||||
llvm::Argument *NthArgument(llvm::Function *func, size_t index);
|
||||
@@ -183,7 +173,10 @@ llvm::Argument *NthArgument(llvm::Function *func, size_t index);
|
||||
llvm::Function *BasicBlockFunction(llvm::Module *module);
|
||||
|
||||
// Return the type of a lifted function.
|
||||
llvm::FunctionType *LiftedFunctionType(llvm::Module *module);
|
||||
//
|
||||
// NOTE(pag): Deprecated. Use `remill::Arch::LiftedFunctionType()` instead.
|
||||
llvm::FunctionType *LiftedFunctionType(llvm::Module *module)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Return a vector of arguments to pass to a lifted function, where the
|
||||
// arguments are derived from `block`.
|
||||
@@ -201,16 +194,25 @@ void ForEachISel(llvm::Module *module, ISelCallback callback);
|
||||
|
||||
// Declare a lifted function of the correct type.
|
||||
llvm::Function *DeclareLiftedFunction(llvm::Module *module,
|
||||
const std::string &name);
|
||||
std::string_view name);
|
||||
|
||||
// Returns the type of a state pointer.
|
||||
llvm::PointerType *StatePointerType(llvm::Module *module);
|
||||
//
|
||||
// NOTE(pag): Deprecated. Use `remill::Arch::StatePointerType()` instead.
|
||||
llvm::PointerType *StatePointerType(llvm::Module *module)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Returns the type of a state pointer.
|
||||
llvm::PointerType *MemoryPointerType(llvm::Module *module);
|
||||
//
|
||||
// NOTE(pag): Deprecated. Use `remill::Arch::MemoryPointerType()` instead.
|
||||
llvm::PointerType *MemoryPointerType(llvm::Module *module)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Returns the type of an address (addr_t in the State.h).
|
||||
llvm::IntegerType *AddressType(llvm::Module *module);
|
||||
//
|
||||
// NOTE(pag): Deprecated. Use `remill::Arch::AddressType()` instead.
|
||||
llvm::IntegerType *AddressType(llvm::Module *module)
|
||||
__attribute__((deprecated));
|
||||
|
||||
using ValueMap = std::unordered_map<llvm::Value *, llvm::Value *>;
|
||||
|
||||
@@ -68,8 +68,8 @@ enum OSName : uint32_t {
|
||||
|
||||
OSName GetOSName(const llvm::Triple &triple);
|
||||
|
||||
OSName GetOSName(std::string name_);
|
||||
OSName GetOSName(std::string_view name_);
|
||||
|
||||
std::string GetOSName(OSName name);
|
||||
std::string_view GetOSName(OSName name);
|
||||
|
||||
} // namespace remill
|
||||
@@ -26,20 +26,20 @@
|
||||
// SOFTWARE.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace remill {
|
||||
namespace Version {
|
||||
namespace version {
|
||||
|
||||
bool HasVersionData();
|
||||
bool HasUncommittedChanges();
|
||||
std::string GetAuthorName();
|
||||
std::string GetAuthorEmail();
|
||||
std::string GetCommitHash();
|
||||
std::string GetCommitDate();
|
||||
std::string GetCommitSubject();
|
||||
std::string GetCommitBody();
|
||||
std::string GetVersionString();
|
||||
bool HasVersionData(void);
|
||||
bool HasUncommittedChanges(void);
|
||||
std::string_view GetAuthorName(void);
|
||||
std::string_view GetAuthorEmail(void);
|
||||
std::string_view GetCommitHash(void);
|
||||
std::string_view GetCommitDate(void);
|
||||
std::string_view GetCommitSubject(void);
|
||||
std::string_view GetCommitBody(void);
|
||||
std::string_view GetVersionString(void);
|
||||
|
||||
} // namespace Version
|
||||
} // namespace version
|
||||
} // namespace remill
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
#define REMILL_AARCH_STRICT_REGNUM
|
||||
|
||||
#include "remill/Arch/AArch64/Decode.h"
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
@@ -42,10 +41,13 @@
|
||||
#include "remill/BC/Version.h"
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
// clang-format off
|
||||
#define ADDRESS_SIZE 64
|
||||
#include "Runtime/State.h"
|
||||
|
||||
#include "Decode.h"
|
||||
|
||||
// clang-format off
|
||||
#define ADDRESS_SIZE_BITS 64
|
||||
#define INCLUDED_FROM_REMILL
|
||||
#include "remill/Arch/AArch64/Runtime/State.h"
|
||||
// clang-format on
|
||||
|
||||
namespace remill {
|
||||
@@ -112,10 +114,10 @@ class AArch64Arch final : public Arch {
|
||||
virtual ~AArch64Arch(void);
|
||||
|
||||
// Returns the name of the stack pointer register.
|
||||
const char *StackPointerRegisterName(void) const override;
|
||||
std::string_view StackPointerRegisterName(void) const override;
|
||||
|
||||
// Returns the name of the program counter register.
|
||||
const char *ProgramCounterRegisterName(void) const override;
|
||||
std::string_view ProgramCounterRegisterName(void) const override;
|
||||
|
||||
// Decode an instruction.
|
||||
bool DecodeInstruction(uint64_t address, std::string_view instr_bytes,
|
||||
@@ -459,14 +461,16 @@ void AArch64Arch::PopulateBasicBlockFunction(llvm::Module *module,
|
||||
|
||||
const auto pc_arg = NthArgument(bb_func, kPCArgNum);
|
||||
const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum);
|
||||
ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, "NEXT_PC"));
|
||||
llvm::StringRef next_pc_name(kNextPCVariableName.data(), kNextPCVariableName.size());
|
||||
ir.CreateStore(pc_arg, ir.CreateAlloca(addr, nullptr, next_pc_name));
|
||||
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "WZR"));
|
||||
ir.CreateStore(zero_u64, ir.CreateAlloca(u64, nullptr, "XZR"));
|
||||
ir.CreateAlloca(u32, nullptr, "IGNORE_WRITE_TO_WZR");
|
||||
ir.CreateAlloca(u64, nullptr, "IGNORE_WRITE_TO_XZR");
|
||||
ir.CreateAlloca(u64, nullptr, "SUPPRESS_WRITEBACK");
|
||||
(void) this->RegisterByName("PC")->AddressOf(state_ptr_arg, ir);
|
||||
|
||||
(void) this->RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir);
|
||||
}
|
||||
|
||||
// Maximum number of bytes in an instruction for this particular architecture.
|
||||
@@ -560,6 +564,7 @@ static RegClass ExtendTypeToRegClass(Extend extend) {
|
||||
case kExtendSXTW: return kRegW;
|
||||
case kExtendSXTX: return kRegX;
|
||||
}
|
||||
return kRegX;
|
||||
}
|
||||
|
||||
static Operand::ShiftRegister::Extend ShiftRegExtendType(Extend extend) {
|
||||
@@ -670,6 +675,7 @@ static std::string RegName(Action action, RegClass rclass, RegUsage rtype,
|
||||
case kRegQ:
|
||||
case kRegV: return RegNameFP(action, rclass, rtype, number);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static uint64_t ReadRegSize(RegClass rclass) {
|
||||
@@ -1171,12 +1177,12 @@ static uint64_t VFPExpandImmToFloat64(uint64_t imm) {
|
||||
}
|
||||
|
||||
// Returns the name of the stack pointer register.
|
||||
const char *AArch64Arch::StackPointerRegisterName(void) const {
|
||||
std::string_view AArch64Arch::StackPointerRegisterName(void) const {
|
||||
return "SP";
|
||||
}
|
||||
|
||||
// Returns the name of the program counter register.
|
||||
const char *AArch64Arch::ProgramCounterRegisterName(void) const {
|
||||
std::string_view AArch64Arch::ProgramCounterRegisterName(void) const {
|
||||
return "PC";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2020 Trail of Bits, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_library(remill_arch_aarch64 STATIC
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Definitions.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/HyperCall.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Intrinsics.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Operators.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Runtime.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h"
|
||||
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Operators.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Types.h"
|
||||
|
||||
Arch.cpp
|
||||
Decode.cpp
|
||||
Decode.h
|
||||
Extract.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(Runtime)
|
||||
|
||||
set_property(TARGET remill_arch_aarch64 PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_link_libraries(remill_arch_aarch64 LINK_PUBLIC
|
||||
remill_settings
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS remill_arch_aarch64
|
||||
ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}"
|
||||
PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}"
|
||||
)
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/Arch/AArch64/Decode.h"
|
||||
#include "Decode.h"
|
||||
|
||||
namespace remill {
|
||||
namespace aarch64 {
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/Arch/AArch64/Decode.h"
|
||||
#include "Decode.h"
|
||||
|
||||
namespace remill {
|
||||
namespace aarch64 {
|
||||
+1
-8
@@ -19,18 +19,11 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "remill/Arch/AArch64/Runtime/State.h"
|
||||
#include "remill/Arch/Float.h"
|
||||
#include "remill/Arch/Runtime/Float.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||
|
||||
// Instructions will be lifted into clones of this function.
|
||||
[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *);
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
} // extern C
|
||||
|
||||
#include "remill/Arch/Runtime/Intrinsics.cpp"
|
||||
@@ -0,0 +1,78 @@
|
||||
# Copyright (c) 2017 Trail of Bits, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(arm_runtime)
|
||||
|
||||
set(ARMRUNTIME_SOURCEFILES
|
||||
Instructions.cpp
|
||||
BasicBlock.cpp
|
||||
|
||||
"${REMILL_LIB_DIR}/Arch/Runtime/Intrinsics.cpp"
|
||||
)
|
||||
|
||||
set_source_files_properties(Instructions.cpp PROPERTIES COMPILE_FLAGS "-O3 -g0")
|
||||
set_source_files_properties(BasicBlock.cpp PROPERTIES COMPILE_FLAGS "-O0 -g3")
|
||||
|
||||
function(add_runtime_helper target_name address_bit_size little_endian)
|
||||
message(" > Generating runtime target: ${target_name}")
|
||||
|
||||
# Visual C++ requires C++14
|
||||
if(WIN32)
|
||||
set(required_cpp_standard "c++14")
|
||||
else()
|
||||
set(required_cpp_standard "c++17")
|
||||
endif()
|
||||
|
||||
add_runtime(${target_name}
|
||||
SOURCES ${ARMRUNTIME_SOURCEFILES}
|
||||
ADDRESS_SIZE ${address_bit_size}
|
||||
DEFINITIONS "LITTLE_ENDIAN=${little_endian}"
|
||||
BCFLAGS "-std=${required_cpp_standard}"
|
||||
INCLUDEDIRECTORIES "${REMILL_INCLUDE_DIR}" "${REMILL_SOURCE_DIR}"
|
||||
INSTALLDESTINATION "${REMILL_INSTALL_SEMANTICS_DIR}"
|
||||
|
||||
DEPENDENCIES
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Float.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Operators.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Intrinsics.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/HyperCall.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Definitions.h"
|
||||
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Operators.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/AArch64/Runtime/Types.h"
|
||||
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/CONVERT.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/BITBYTE.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/SIMD.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/COND.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/BINARY.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/SHIFT.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/BRANCH.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/DATAXFER.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/CALL_RET.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/MISC.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/FLAGS.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/LOGICAL.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/AArch64/Semantics/SYSTEM.cpp"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
#add_runtime_helper(aarch64be 64 0)
|
||||
add_runtime_helper(aarch64 64 1)
|
||||
endif()
|
||||
+14
-14
@@ -19,7 +19,7 @@
|
||||
#include <cmath>
|
||||
|
||||
// clang-format off
|
||||
#include "remill/Arch/Float.h"
|
||||
#include "remill/Arch/Runtime/Float.h"
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
#include "remill/Arch/AArch64/Runtime/State.h"
|
||||
@@ -103,19 +103,19 @@ DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported;
|
||||
DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction;
|
||||
|
||||
// clang-format off
|
||||
#include "remill/Arch/AArch64/Semantics/FLAGS.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/FLAGS.cpp"
|
||||
|
||||
#include "remill/Arch/AArch64/Semantics/BINARY.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/BRANCH.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/COND.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/CONVERT.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/LOGICAL.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/MISC.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/SHIFT.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/SIMD.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/SYSTEM.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/BINARY.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/BITBYTE.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/BRANCH.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/CALL_RET.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/COND.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/CONVERT.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/DATAXFER.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/LOGICAL.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/MISC.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/SHIFT.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/SIMD.cpp"
|
||||
#include "lib/Arch/AArch64/Semantics/SYSTEM.cpp"
|
||||
|
||||
// clang-format on
|
||||
@@ -14,6 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Disable the "loop not unrolled warnings"
|
||||
#pragma clang diagnostic ignored "-Wpass-failed"
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename S>
|
||||
@@ -80,11 +80,15 @@ static unsigned AddressSize(ArchName arch_name) {
|
||||
return 0;
|
||||
case kArchX86:
|
||||
case kArchX86_AVX:
|
||||
case kArchX86_AVX512: return 32;
|
||||
case kArchX86_AVX512:
|
||||
case kArchSparc32:
|
||||
return 32;
|
||||
case kArchAMD64:
|
||||
case kArchAMD64_AVX:
|
||||
case kArchAMD64_AVX512:
|
||||
case kArchAArch64LittleEndian: return 64;
|
||||
case kArchAArch64LittleEndian:
|
||||
case kArchSparc64:
|
||||
return 64;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -198,12 +202,27 @@ auto Arch::Build(llvm::LLVMContext *context_, OSName os_name_,
|
||||
DLOG(INFO) << "Using architecture: AMD64, feature set: AVX512";
|
||||
return GetX86(context_, os_name_, arch_name_);
|
||||
}
|
||||
|
||||
case kArchSparc32: {
|
||||
DLOG(INFO) << "Using architecture: 32-bit SPARC";
|
||||
return GetSPARC(context_, os_name_, arch_name_);
|
||||
}
|
||||
|
||||
case kArchSparc64: {
|
||||
DLOG(INFO) << "Using architecture: 64-bit SPARC";
|
||||
return GetSPARC64(context_, os_name_, arch_name_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Arch *Arch::Get(llvm::LLVMContext &context, OSName os,
|
||||
ArchName arch_name) {
|
||||
return Arch::Build(&context, os, arch_name).release();
|
||||
auto Arch::Get(llvm::LLVMContext &context, std::string_view os,
|
||||
std::string_view arch_name) -> ArchPtr {
|
||||
return Arch::Build(&context, GetOSName(os), GetArchName(arch_name));
|
||||
}
|
||||
|
||||
auto Arch::Get(llvm::LLVMContext &context, OSName os,
|
||||
ArchName arch_name) -> ArchPtr {
|
||||
return Arch::Build(&context, os, arch_name);
|
||||
}
|
||||
|
||||
auto Arch::GetHostArch(llvm::LLVMContext &ctx) -> ArchPtr {
|
||||
@@ -221,6 +240,13 @@ llvm::StructType *Arch::StateStructType(void) const {
|
||||
return impl->state_type;
|
||||
}
|
||||
|
||||
// Pointer to a state structure type.
|
||||
llvm::PointerType *Arch::StatePointerType(void) const {
|
||||
CHECK(impl)
|
||||
<< "Have you not run `PrepareModule` on a loaded semantics module?";
|
||||
return llvm::PointerType::get(impl->state_type, 0);
|
||||
}
|
||||
|
||||
// Return the type of an address, i.e. `addr_t` in the semantics.
|
||||
llvm::IntegerType *Arch::AddressType(void) const {
|
||||
return llvm::IntegerType::get(*context, address_size);
|
||||
@@ -259,12 +285,14 @@ void Arch::ForEachRegister(std::function<void(const Register *)> cb) const {
|
||||
}
|
||||
|
||||
// Return information about a register, given its name.
|
||||
const Register *Arch::RegisterByName(const std::string &name) const {
|
||||
auto reg_it = impl->reg_by_name.find(name);
|
||||
if (reg_it == impl->reg_by_name.end()) {
|
||||
const Register *Arch::RegisterByName(std::string_view name_) const {
|
||||
std::string name(name_.data(), name_.size());
|
||||
auto [curr_val_it, added] = impl->reg_by_name.emplace(std::move(name),
|
||||
nullptr);
|
||||
if (added) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return reg_it->second;
|
||||
return curr_val_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,21 +331,8 @@ struct AvailableArchs {
|
||||
|
||||
AvailableArchs::ArchMap AvailableArchs::cached = {};
|
||||
|
||||
static const Arch *GetOrCreate(llvm::LLVMContext &ctx, OSName os,
|
||||
ArchName name) {
|
||||
return AvailableArchs::GetOrCreate(&ctx, os, name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
const Arch *GetHostArch(llvm::LLVMContext &ctx) {
|
||||
return GetOrCreate(ctx, GetOSName(REMILL_OS), GetArchName(REMILL_ARCH));
|
||||
}
|
||||
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &ctx) {
|
||||
return GetOrCreate(ctx, GetOSName(FLAGS_os), GetArchName(FLAGS_arch));
|
||||
}
|
||||
|
||||
remill::Arch::ArchPtr Arch::GetModuleArch(const llvm::Module &module) {
|
||||
const llvm::Triple triple = llvm::Triple(module.getTargetTriple());
|
||||
return remill::Arch::Build(&module.getContext(), GetOSName(triple),
|
||||
@@ -346,6 +361,14 @@ bool Arch::IsAArch64(void) const {
|
||||
return remill::kArchAArch64LittleEndian == arch_name;
|
||||
}
|
||||
|
||||
bool Arch::IsSPARC32(void) const {
|
||||
return remill::kArchSparc32 == arch_name;
|
||||
}
|
||||
|
||||
bool Arch::IsSPARC64(void) const {
|
||||
return remill::kArchSparc64 == arch_name;
|
||||
}
|
||||
|
||||
bool Arch::IsWindows(void) const {
|
||||
return remill::kOSWindows == os_name;
|
||||
}
|
||||
@@ -366,10 +389,11 @@ namespace {
|
||||
|
||||
// These variables must always be defined within `__remill_basic_block`.
|
||||
static bool BlockHasSpecialVars(llvm::Function *basic_block) {
|
||||
return FindVarInFunction(basic_block, "STATE", true) &&
|
||||
FindVarInFunction(basic_block, "MEMORY", true) &&
|
||||
FindVarInFunction(basic_block, "PC", true) &&
|
||||
FindVarInFunction(basic_block, "BRANCH_TAKEN", true);
|
||||
return FindVarInFunction(basic_block, kStateVariableName, true) &&
|
||||
FindVarInFunction(basic_block, kMemoryVariableName, true) &&
|
||||
FindVarInFunction(basic_block, kPCVariableName, true) &&
|
||||
FindVarInFunction(basic_block, kNextPCVariableName, true) &&
|
||||
FindVarInFunction(basic_block, kBranchTakenVariableName, true);
|
||||
}
|
||||
|
||||
// Add attributes to llvm::Argument in a way portable across LLVMs
|
||||
@@ -619,12 +643,14 @@ void Arch::PrepareModule(llvm::Module *mod) const {
|
||||
PrepareModuleDataLayout(mod);
|
||||
}
|
||||
|
||||
void Arch::AddRegister(const char *reg_name_, llvm::Type *val_type,
|
||||
size_t offset, const char *parent_reg_name) const {
|
||||
const Register *Arch::AddRegister(
|
||||
const char *reg_name_, llvm::Type *val_type, size_t offset,
|
||||
const char *parent_reg_name) const {
|
||||
|
||||
const std::string reg_name(reg_name_);
|
||||
auto ® = impl->reg_by_name[reg_name];
|
||||
if (reg) {
|
||||
return;
|
||||
return reg;
|
||||
}
|
||||
|
||||
const auto dl = this->DataLayout();
|
||||
@@ -635,8 +661,23 @@ void Arch::AddRegister(const char *reg_name_, llvm::Type *val_type,
|
||||
parent_reg = impl->reg_by_name[parent_reg_name];
|
||||
}
|
||||
|
||||
llvm::SmallVector<llvm::Value *, 8> gep_index_list;
|
||||
gep_index_list.push_back(
|
||||
llvm::Constant::getNullValue(llvm::Type::getInt32Ty(*context)));
|
||||
|
||||
auto [gep_offset, gep_type_at_offset] = BuildIndexes(
|
||||
dl, impl->state_type, 0, offset, gep_index_list);
|
||||
|
||||
if (!val_type) {
|
||||
CHECK_EQ(gep_offset, offset);
|
||||
val_type = gep_type_at_offset;
|
||||
}
|
||||
|
||||
auto reg_impl = new Register(reg_name, offset, dl.getTypeAllocSize(val_type),
|
||||
val_type, parent_reg, impl.get());
|
||||
reg_impl->gep_index_list = std::move(gep_index_list);
|
||||
reg_impl->gep_offset = gep_offset;
|
||||
reg_impl->gep_type_at_offset = gep_type_at_offset;
|
||||
reg = reg_impl;
|
||||
impl->registers.emplace_back(reg_impl);
|
||||
|
||||
@@ -644,11 +685,6 @@ void Arch::AddRegister(const char *reg_name_, llvm::Type *val_type,
|
||||
const_cast<Register *>(reg->parent)->children.push_back(reg);
|
||||
}
|
||||
|
||||
reg_impl->gep_index_list.push_back(
|
||||
llvm::Constant::getNullValue(llvm::Type::getInt32Ty(*context)));
|
||||
std::tie(reg_impl->gep_offset, reg_impl->gep_type_at_offset) = BuildIndexes(
|
||||
dl, impl->state_type, 0, reg->offset, reg_impl->gep_index_list);
|
||||
|
||||
// Provide easy access to registers at specific offsets in the `State`
|
||||
// structure.
|
||||
for (auto i = reg->offset; i < (reg->offset + reg->size); ++i) {
|
||||
@@ -660,6 +696,8 @@ void Arch::AddRegister(const char *reg_name_, llvm::Type *val_type,
|
||||
reg_at_offset = reg;
|
||||
}
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
// Get all of the register information from the prepared module.
|
||||
@@ -673,13 +711,14 @@ void Arch::InitFromSemanticsModule(llvm::Module *module) const {
|
||||
|
||||
const auto &dl = module->getDataLayout();
|
||||
const auto basic_block = BasicBlockFunction(module);
|
||||
const auto state_ptr_type = ::remill::StatePointerType(module);
|
||||
const auto state_ptr_type = NthArgument(basic_block, kStatePointerArgNum)->getType();
|
||||
const auto state_type =
|
||||
llvm::dyn_cast<llvm::StructType>(state_ptr_type->getElementType());
|
||||
llvm::dyn_cast<llvm::StructType>(state_ptr_type->getPointerElementType());
|
||||
|
||||
impl->state_type = state_type;
|
||||
impl->reg_by_offset.resize(dl.getTypeAllocSize(state_type));
|
||||
impl->memory_type = ::remill::MemoryPointerType(module);
|
||||
impl->memory_type = llvm::dyn_cast<llvm::PointerType>(
|
||||
NthArgument(basic_block, kMemoryPointerArgNum)->getType());
|
||||
impl->lifted_function_type = basic_block->getFunctionType();
|
||||
impl->reg_md_id = context->getMDKindID("remill_register");
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright (c) 2020 Trail of Bits, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_library(remill_arch STATIC
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Arch.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Instruction.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Name.h"
|
||||
|
||||
Arch.cpp
|
||||
Instruction.cpp
|
||||
Name.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(AArch64)
|
||||
add_subdirectory(SPARC32)
|
||||
add_subdirectory(SPARC64)
|
||||
add_subdirectory(X86)
|
||||
|
||||
set_property(TARGET remill_arch PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_link_libraries(remill_arch LINK_PUBLIC
|
||||
remill_settings
|
||||
remill_arch_aarch64
|
||||
remill_arch_sparc32
|
||||
remill_arch_sparc64
|
||||
remill_arch_x86
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS remill_arch
|
||||
ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}"
|
||||
PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}"
|
||||
)
|
||||
@@ -272,6 +272,8 @@ std::string Instruction::Serialize(void) const {
|
||||
case kArchX86_AVX:
|
||||
case kArchX86_AVX512: ss << "X86"; break;
|
||||
case kArchAArch64LittleEndian: ss << "AArch64"; break;
|
||||
case kArchSparc32: ss << "SPARC32"; break;
|
||||
case kArchSparc64: ss << "SPARC64"; break;
|
||||
}
|
||||
|
||||
ss << " " << std::hex << pc;
|
||||
@@ -29,7 +29,7 @@ ArchName GetArchName(const llvm::Triple &triple) {
|
||||
}
|
||||
}
|
||||
|
||||
ArchName GetArchName(const std::string &arch_name) {
|
||||
ArchName GetArchName(std::string_view arch_name) {
|
||||
if (arch_name == "x86") {
|
||||
return kArchX86;
|
||||
|
||||
@@ -51,23 +51,36 @@ ArchName GetArchName(const std::string &arch_name) {
|
||||
} else if (arch_name == "aarch64") {
|
||||
return kArchAArch64LittleEndian;
|
||||
|
||||
} else if (arch_name == "sparc32") {
|
||||
return kArchSparc32;
|
||||
|
||||
} else if (arch_name == "sparc64") {
|
||||
return kArchSparc64;
|
||||
|
||||
} else {
|
||||
return kArchInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetArchName(ArchName arch_name) {
|
||||
switch (arch_name) {
|
||||
case kArchInvalid: return "invalid";
|
||||
case kArchX86: return "x86";
|
||||
case kArchX86_AVX: return "x86_avx";
|
||||
case kArchX86_AVX512: return "x86_avx512";
|
||||
case kArchAMD64: return "amd64";
|
||||
case kArchAMD64_AVX: return "amd64_avx";
|
||||
case kArchAMD64_AVX512: return "amd64_avx512";
|
||||
case kArchAArch64LittleEndian: return "aarch64";
|
||||
}
|
||||
return "invalid";
|
||||
namespace {
|
||||
|
||||
static const std::string_view kArchNames[] = {
|
||||
[kArchInvalid] = "invalid",
|
||||
[kArchX86] = "x86",
|
||||
[kArchX86_AVX] = "x86_avx",
|
||||
[kArchX86_AVX512] = "x86_avx512",
|
||||
[kArchAMD64] = "amd64",
|
||||
[kArchAMD64_AVX] = "amd64_avx",
|
||||
[kArchAMD64_AVX512] = "amd64_avx512",
|
||||
[kArchAArch64LittleEndian] = "aarch64",
|
||||
[kArchSparc32] = "sparc32",
|
||||
[kArchSparc64] = "sparc64",
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string_view GetArchName(ArchName arch_name) {
|
||||
return kArchNames[arch_name];
|
||||
}
|
||||
|
||||
} // namespace remill
|
||||
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
#include "remill/BC/ABI.h"
|
||||
#include "remill/BC/Util.h"
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
#include "Decode.h"
|
||||
|
||||
// clang-format off
|
||||
#define ADDRESS_SIZE_BITS 32
|
||||
#define INCLUDED_FROM_REMILL
|
||||
#include "remill/Arch/SPARC32/Runtime/State.h"
|
||||
// clang-format on
|
||||
|
||||
namespace remill {
|
||||
namespace sparc {
|
||||
namespace {
|
||||
static const std::string_view kSPRegName = "sp";
|
||||
static const std::string_view kPCRegName = "pc";
|
||||
} // namespace
|
||||
|
||||
|
||||
const std::string_view kCCRName[4] = {
|
||||
"icc", {}, "xcc", {}
|
||||
};
|
||||
|
||||
const std::string_view kFCCRName[8] = {
|
||||
"fcc0", "fcc1", "fcc2", "fcc3",
|
||||
"icc", {}, "xcc", {}
|
||||
};
|
||||
|
||||
const std::string_view kReadIntRegName[32] = {
|
||||
"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
|
||||
"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
|
||||
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
|
||||
"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
|
||||
};
|
||||
|
||||
const std::string_view kWriteIntRegName[32] = {
|
||||
"ignore_write_to_g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
|
||||
"o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
|
||||
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
|
||||
"i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7"
|
||||
};
|
||||
|
||||
const std::string_view kCondName[16] = {
|
||||
[0b0000] = "N",
|
||||
[0b0001] = "E",
|
||||
[0b0010] = "LE",
|
||||
[0b0011] = "L",
|
||||
[0b0100] = "LEU",
|
||||
[0b0101] = "CS",
|
||||
[0b0110] = "NEG",
|
||||
[0b0111] = "VS",
|
||||
[0b1000] = "A",
|
||||
[0b1001] = "NE",
|
||||
[0b1010] = "G",
|
||||
[0b1011] = "GE",
|
||||
[0b1100] = "GU",
|
||||
[0b1101] = "CC",
|
||||
[0b1110] = "POS",
|
||||
[0b1111] = "VC",
|
||||
};
|
||||
|
||||
const std::string_view kFCondName[16] = {
|
||||
[0b0000] = "N",
|
||||
[0b0001] = "NE",
|
||||
[0b0010] = "LG",
|
||||
[0b0011] = "UL",
|
||||
[0b0100] = "L",
|
||||
[0b0101] = "UG",
|
||||
[0b0110] = "G",
|
||||
[0b0111] = "U",
|
||||
[0b1000] = "A",
|
||||
[0b1001] = "E",
|
||||
[0b1010] = "UE",
|
||||
[0b1011] = "GE",
|
||||
[0b1100] = "UGE",
|
||||
[0b1101] = "LE",
|
||||
[0b1110] = "ULE",
|
||||
[0b1111] = "O"
|
||||
};
|
||||
|
||||
const std::string_view kRCondName[8] = {
|
||||
[0b000] = {},
|
||||
[0b001] = "Z",
|
||||
[0b010] = "LEZ",
|
||||
[0b011] = "LZ",
|
||||
[0b100] = {},
|
||||
[0b101] = "NZ",
|
||||
[0b110] = "GZ",
|
||||
[0b111] = "GEZ"
|
||||
};
|
||||
|
||||
void AddSrcRegop(Instruction &inst, const char *reg_name, unsigned size) {
|
||||
inst.operands.emplace_back();
|
||||
auto &op = inst.operands.back();
|
||||
op.type = Operand::kTypeRegister;
|
||||
op.size = size;
|
||||
op.action = Operand::kActionRead;
|
||||
op.reg.name = reg_name;
|
||||
op.reg.size = size;
|
||||
}
|
||||
|
||||
void AddDestRegop(Instruction &inst, const char *reg_name, unsigned size) {
|
||||
inst.operands.emplace_back();
|
||||
auto &op = inst.operands.back();
|
||||
op.type = Operand::kTypeRegister;
|
||||
op.size = size;
|
||||
op.action = Operand::kActionWrite;
|
||||
op.reg.name = reg_name;
|
||||
op.reg.size = size;
|
||||
}
|
||||
|
||||
void AddImmop(Instruction &inst, uint64_t imm,
|
||||
unsigned size, bool is_signed) {
|
||||
inst.operands.emplace_back();
|
||||
auto &op = inst.operands.back();
|
||||
op.type = Operand::kTypeImmediate;
|
||||
op.size = size;
|
||||
op.action = Operand::kActionRead;
|
||||
op.imm.val = imm;
|
||||
op.imm.is_signed = is_signed;
|
||||
}
|
||||
|
||||
|
||||
class SPARC32Arch final : public Arch {
|
||||
public:
|
||||
SPARC32Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_)
|
||||
: Arch(context_, os_name_, arch_name_) {}
|
||||
|
||||
virtual ~SPARC32Arch(void) = default;
|
||||
|
||||
// Returns the name of the stack pointer register.
|
||||
std::string_view StackPointerRegisterName(void) const final {
|
||||
return kSPRegName;
|
||||
}
|
||||
|
||||
// Returns the name of the program counter register.
|
||||
std::string_view ProgramCounterRegisterName(void) const final {
|
||||
return kPCRegName;
|
||||
}
|
||||
|
||||
// Maximum number of bytes in an instruction.
|
||||
uint64_t MaxInstructionSize(void) const final {
|
||||
return 8; // To handle `SET` idioms.
|
||||
}
|
||||
|
||||
// Default calling convention for this architecture.
|
||||
llvm::CallingConv::ID DefaultCallingConv(void) const final {
|
||||
return llvm::CallingConv::C;
|
||||
}
|
||||
|
||||
// Populate the `__remill_basic_block` function with variables.
|
||||
void PopulateBasicBlockFunction(llvm::Module *module,
|
||||
llvm::Function *bb_func) const override;
|
||||
|
||||
llvm::Triple Triple(void) const final;
|
||||
llvm::DataLayout DataLayout(void) const final;
|
||||
|
||||
// Decode an instruction.
|
||||
bool DecodeInstruction(
|
||||
uint64_t address, std::string_view instr_bytes,
|
||||
Instruction &inst) const final;
|
||||
|
||||
// Returns `true` if memory access are little endian byte ordered.
|
||||
bool MemoryAccessIsLittleEndian(void) const final {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns `true` if a given instruction might have a delay slot.
|
||||
bool MayHaveDelaySlot(const Instruction &inst) const final;
|
||||
|
||||
// Returns `true` if we should lift the semantics of `next_inst` as a delay
|
||||
// slot of `inst`. The `branch_taken_path` tells us whether we are in the
|
||||
// context of the taken path of a branch or the not-taken path of a branch.
|
||||
virtual bool NextInstructionIsDelayed(const Instruction &inst,
|
||||
const Instruction &next_inst,
|
||||
bool branch_taken_path) const final;
|
||||
};
|
||||
|
||||
// Populate the `__remill_basic_block` function with variables.
|
||||
void SPARC32Arch::PopulateBasicBlockFunction(llvm::Module *module,
|
||||
llvm::Function *bb_func) const {
|
||||
|
||||
#define OFFSET_OF(type, access) \
|
||||
(reinterpret_cast<uintptr_t>(&reinterpret_cast<const volatile char &>( \
|
||||
static_cast<type *>(nullptr)->access)))
|
||||
|
||||
#define REG(name, access, type) \
|
||||
AddRegister(#name, type, OFFSET_OF(SPARCState, access), nullptr)
|
||||
|
||||
#define SUB_REG(name, access, type, parent_reg_name) \
|
||||
AddRegister(#name, type, OFFSET_OF(SPARCState, access), #parent_reg_name)
|
||||
|
||||
auto &context = module->getContext();
|
||||
auto u8 = llvm::Type::getInt8Ty(context);
|
||||
auto u32 = llvm::Type::getInt32Ty(context);
|
||||
auto u64 = llvm::Type::getInt64Ty(context);
|
||||
auto u128 = llvm::Type::getInt128Ty(context);
|
||||
auto f32 = llvm::Type::getFloatTy(context);
|
||||
auto f64 = llvm::Type::getDoubleTy(context);
|
||||
|
||||
auto zero_u8 = llvm::Constant::getNullValue(u8);
|
||||
auto zero_u32 = llvm::Constant::getNullValue(u32);
|
||||
|
||||
const auto entry_block = &bb_func->getEntryBlock();
|
||||
llvm::IRBuilder<> ir(entry_block);
|
||||
|
||||
REG(pc, pc.dword, u32);
|
||||
SUB_REG(PC, pc.dword, u32, pc);
|
||||
|
||||
REG(npc, next_pc.dword, u32);
|
||||
SUB_REG(NEXT_PC, next_pc.dword, u32, npc);
|
||||
|
||||
REG(sp, gpr.o6.dword, u32);
|
||||
SUB_REG(SP, gpr.o6.dword, u32, sp);
|
||||
|
||||
REG(fp, gpr.i6.dword, u32);
|
||||
SUB_REG(FP, gpr.i6.dword, u32, fp);
|
||||
|
||||
REG(i0, gpr.i0.dword, u32);
|
||||
REG(i1, gpr.i1.dword, u32);
|
||||
REG(i2, gpr.i2.dword, u32);
|
||||
REG(i3, gpr.i3.dword, u32);
|
||||
REG(i4, gpr.i4.dword, u32);
|
||||
REG(i5, gpr.i5.dword, u32);
|
||||
SUB_REG(i6, gpr.i6.dword, u32, fp);
|
||||
REG(i7, gpr.i7.dword, u32);
|
||||
REG(l0, gpr.l0.dword, u32);
|
||||
REG(l1, gpr.l1.dword, u32);
|
||||
REG(l2, gpr.l2.dword, u32);
|
||||
REG(l3, gpr.l3.dword, u32);
|
||||
REG(l4, gpr.l4.dword, u32);
|
||||
REG(l5, gpr.l5.dword, u32);
|
||||
REG(l6, gpr.l6.dword, u32);
|
||||
REG(l7, gpr.l7.dword, u32);
|
||||
REG(o0, gpr.o0.dword, u32);
|
||||
REG(o1, gpr.o1.dword, u32);
|
||||
REG(o2, gpr.o2.dword, u32);
|
||||
REG(o3, gpr.o3.dword, u32);
|
||||
REG(o4, gpr.o4.dword, u32);
|
||||
REG(o5, gpr.o5.dword, u32);
|
||||
SUB_REG(o6, gpr.o6.dword, u32, sp);
|
||||
REG(o7, gpr.o7.dword, u32);
|
||||
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "g0"), false);
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "ignore_write_to_g0"), false);
|
||||
|
||||
REG(g1, gpr.g1.dword, u32);
|
||||
REG(g2, gpr.g2.dword, u32);
|
||||
REG(g3, gpr.g3.dword, u32);
|
||||
REG(g4, gpr.g4.dword, u32);
|
||||
REG(g5, gpr.g5.dword, u32);
|
||||
REG(g6, gpr.g6.dword, u32);
|
||||
REG(g7, gpr.g7.dword, u32);
|
||||
|
||||
// Ancillary State Register
|
||||
REG(y, asr.yreg.dword, u32);
|
||||
REG(asi, asr.asi_flat, u32);
|
||||
REG(tick, asr.tick, u64);
|
||||
REG(fprs, asr.fprs_flat, u32);
|
||||
REG(gsr, asr.gsr.flat, u64);
|
||||
REG(softint, asr.softint, u64);
|
||||
REG(stick, asr.stick, u64);
|
||||
REG(stick_cmpr, asr.stick_cmpr, u64);
|
||||
REG(cfr, asr.cfr, u64);
|
||||
|
||||
// this is for unknown asr to avoid crash.
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "asr"), false);
|
||||
|
||||
REG(icc_c, asr.ccr.icc.c, u8);
|
||||
REG(icc_v, asr.ccr.icc.v, u8);
|
||||
REG(icc_z, asr.ccr.icc.z, u8);
|
||||
REG(icc_n, asr.ccr.icc.n, u8);
|
||||
|
||||
REG(xcc_c, asr.ccr.xcc.c, u8);
|
||||
REG(xcc_v, asr.ccr.xcc.v, u8);
|
||||
REG(xcc_z, asr.ccr.xcc.z, u8);
|
||||
REG(xcc_n, asr.ccr.xcc.n, u8);
|
||||
|
||||
REG(ccf_fcc0, fsr.fcc0, u8);
|
||||
REG(ccf_fcc1, fsr.fcc1, u8);
|
||||
REG(ccf_fcc2, fsr.fcc2, u8);
|
||||
REG(ccf_fcc3, fsr.fcc3, u8);
|
||||
|
||||
REG(ccc, csr.ccc, u8);
|
||||
|
||||
REG(fsr_aexc, fsr.aexc, u8);
|
||||
REG(fsr_cexc, fsr.cexc, u8);
|
||||
|
||||
REG(v0, fpreg.v[0], u128);
|
||||
REG(v1, fpreg.v[1], u128);
|
||||
REG(v2, fpreg.v[2], u128);
|
||||
REG(v3, fpreg.v[3], u128);
|
||||
REG(v4, fpreg.v[4], u128);
|
||||
REG(v5, fpreg.v[5], u128);
|
||||
REG(v6, fpreg.v[6], u128);
|
||||
REG(v7, fpreg.v[7], u128);
|
||||
|
||||
SUB_REG(f0, fpreg.v[0].floats.elems[0], f32, v0);
|
||||
SUB_REG(f1, fpreg.v[0].floats.elems[1], f32, v0);
|
||||
SUB_REG(f2, fpreg.v[0].floats.elems[2], f32, v0);
|
||||
SUB_REG(f3, fpreg.v[0].floats.elems[3], f32, v0);
|
||||
SUB_REG(f4, fpreg.v[1].floats.elems[0], f32, v1);
|
||||
SUB_REG(f5, fpreg.v[1].floats.elems[1], f32, v1);
|
||||
SUB_REG(f6, fpreg.v[1].floats.elems[2], f32, v1);
|
||||
SUB_REG(f7, fpreg.v[1].floats.elems[3], f32, v1);
|
||||
SUB_REG(f8, fpreg.v[2].floats.elems[0], f32, v2);
|
||||
SUB_REG(f9, fpreg.v[2].floats.elems[1], f32, v2);
|
||||
SUB_REG(f10, fpreg.v[2].floats.elems[2], f32, v2);
|
||||
SUB_REG(f11, fpreg.v[2].floats.elems[3], f32, v2);
|
||||
SUB_REG(f12, fpreg.v[3].floats.elems[0], f32, v3);
|
||||
SUB_REG(f13, fpreg.v[3].floats.elems[1], f32, v3);
|
||||
SUB_REG(f14, fpreg.v[3].floats.elems[2], f32, v3);
|
||||
SUB_REG(f15, fpreg.v[3].floats.elems[3], f32, v3);
|
||||
SUB_REG(f16, fpreg.v[4].floats.elems[0], f32, v4);
|
||||
SUB_REG(f17, fpreg.v[4].floats.elems[1], f32, v4);
|
||||
SUB_REG(f18, fpreg.v[4].floats.elems[2], f32, v4);
|
||||
SUB_REG(f19, fpreg.v[4].floats.elems[3], f32, v4);
|
||||
SUB_REG(f20, fpreg.v[5].floats.elems[0], f32, v5);
|
||||
SUB_REG(f21, fpreg.v[5].floats.elems[1], f32, v5);
|
||||
SUB_REG(f22, fpreg.v[5].floats.elems[2], f32, v5);
|
||||
SUB_REG(f23, fpreg.v[5].floats.elems[3], f32, v5);
|
||||
SUB_REG(f24, fpreg.v[6].floats.elems[0], f32, v6);
|
||||
SUB_REG(f25, fpreg.v[6].floats.elems[1], f32, v6);
|
||||
SUB_REG(f26, fpreg.v[6].floats.elems[2], f32, v6);
|
||||
SUB_REG(f27, fpreg.v[6].floats.elems[3], f32, v6);
|
||||
SUB_REG(f28, fpreg.v[7].floats.elems[0], f32, v7);
|
||||
SUB_REG(f29, fpreg.v[7].floats.elems[1], f32, v7);
|
||||
SUB_REG(f30, fpreg.v[7].floats.elems[2], f32, v7);
|
||||
SUB_REG(f31, fpreg.v[7].floats.elems[3], f32, v7);
|
||||
|
||||
SUB_REG(d0, fpreg.v[0].doubles.elems[0], f64, v0);
|
||||
SUB_REG(d2, fpreg.v[0].doubles.elems[1], f64, v0);
|
||||
SUB_REG(d4, fpreg.v[1].doubles.elems[0], f64, v1);
|
||||
SUB_REG(d6, fpreg.v[1].doubles.elems[1], f64, v1);
|
||||
SUB_REG(d8, fpreg.v[2].doubles.elems[0], f64, v2);
|
||||
SUB_REG(d10, fpreg.v[2].doubles.elems[1], f64, v2);
|
||||
SUB_REG(d12, fpreg.v[3].doubles.elems[0], f64, v3);
|
||||
SUB_REG(d14, fpreg.v[3].doubles.elems[1], f64, v3);
|
||||
SUB_REG(d16, fpreg.v[4].doubles.elems[0], f64, v4);
|
||||
SUB_REG(d18, fpreg.v[4].doubles.elems[1], f64, v4);
|
||||
SUB_REG(d20, fpreg.v[5].doubles.elems[0], f64, v5);
|
||||
SUB_REG(d22, fpreg.v[5].doubles.elems[1], f64, v5);
|
||||
SUB_REG(d24, fpreg.v[6].doubles.elems[0], f64, v6);
|
||||
SUB_REG(d26, fpreg.v[6].doubles.elems[1], f64, v6);
|
||||
SUB_REG(d28, fpreg.v[7].doubles.elems[0], f64, v7);
|
||||
SUB_REG(d30, fpreg.v[7].doubles.elems[1], f64, v7);
|
||||
|
||||
// NOTE(pag): This is a bit of a lie, but kind of like in x87 with 80-bit
|
||||
// extended precision, we treat quad precision floats as being
|
||||
// doubles.
|
||||
SUB_REG(q0, fpreg.v[0].doubles.elems[0], f64, v0);
|
||||
SUB_REG(q4, fpreg.v[1].doubles.elems[0], f64, v1);
|
||||
SUB_REG(q8, fpreg.v[2].doubles.elems[0], f64, v2);
|
||||
SUB_REG(q12, fpreg.v[3].doubles.elems[0], f64, v3);
|
||||
SUB_REG(q16, fpreg.v[4].doubles.elems[0], f64, v4);
|
||||
SUB_REG(q20, fpreg.v[5].doubles.elems[0], f64, v5);
|
||||
SUB_REG(q24, fpreg.v[6].doubles.elems[0], f64, v6);
|
||||
SUB_REG(q28, fpreg.v[7].doubles.elems[0], f64, v7);
|
||||
|
||||
// NOTE(pag): Passing `nullptr` as the type will force `Arch::AddRegister`
|
||||
// to infer the type based on what it finds. It's a pointer to
|
||||
// a structure type, so we can check that.
|
||||
const auto prev_window_link = REG(PREV_WINDOW_LINK, window, nullptr);
|
||||
CHECK(prev_window_link->type->isPointerTy());
|
||||
const auto window_type = prev_window_link->type->getPointerElementType();
|
||||
CHECK(window_type->isStructTy());
|
||||
|
||||
auto window = ir.CreateAlloca(window_type, nullptr, "WINDOW");
|
||||
ir.CreateAlloca(prev_window_link->type, nullptr, "PREV_WINDOW");
|
||||
|
||||
// `WINDOW_LINK = &(WINDOW->prev_window);`
|
||||
llvm::Value *gep_indexes[2] = {zero_u32, llvm::ConstantInt::get(u32, 33)};
|
||||
auto window_link = ir.CreateInBoundsGEP(window_type, window, gep_indexes, "WINDOW_LINK");
|
||||
auto nullptr_window = llvm::Constant::getNullValue(prev_window_link->type);
|
||||
ir.CreateStore(nullptr_window, window_link, false);
|
||||
|
||||
ir.CreateStore(zero_u8, ir.CreateAlloca(u8, nullptr, "IGNORE_BRANCH_TAKEN"), false);
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_PC"), false);
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_NEXT_PC"), false);
|
||||
ir.CreateStore(zero_u32, ir.CreateAlloca(u32, nullptr, "IGNORE_RETURN_PC"), false);
|
||||
|
||||
const auto pc_arg = NthArgument(bb_func, kPCArgNum);
|
||||
const auto state_ptr_arg = NthArgument(bb_func, kStatePointerArgNum);
|
||||
|
||||
(void) RegisterByName(kNextPCVariableName)->AddressOf(state_ptr_arg, ir);
|
||||
|
||||
ir.CreateStore(
|
||||
pc_arg, RegisterByName(kPCVariableName)->AddressOf(state_ptr_arg, ir),
|
||||
false);
|
||||
}
|
||||
|
||||
llvm::Triple SPARC32Arch::Triple(void) const {
|
||||
auto triple = BasicTriple();
|
||||
triple.setArch(llvm::Triple::sparc);
|
||||
return triple;
|
||||
}
|
||||
|
||||
llvm::DataLayout SPARC32Arch::DataLayout(void) const {
|
||||
return llvm::DataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64");
|
||||
}
|
||||
|
||||
// Returns `true` if a given instruction might have a delay slot.
|
||||
bool SPARC32Arch::MayHaveDelaySlot(const Instruction &inst) const {
|
||||
return inst.has_branch_taken_delay_slot ||
|
||||
inst.has_branch_not_taken_delay_slot;
|
||||
}
|
||||
|
||||
// Returns `true` if we should lift the semantics of `next_inst` as a delay
|
||||
// slot of `inst`. The `branch_taken_path` tells us whether we are in the
|
||||
// context of the taken path of a branch or the not-taken path of a branch.
|
||||
bool SPARC32Arch::NextInstructionIsDelayed(const Instruction &inst,
|
||||
const Instruction &next_inst,
|
||||
bool branch_taken_path) const {
|
||||
if (inst.delayed_pc != next_inst.pc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (branch_taken_path) {
|
||||
return inst.has_branch_taken_delay_slot;
|
||||
} else {
|
||||
return inst.has_branch_not_taken_delay_slot;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode an instruction.
|
||||
bool SPARC32Arch::DecodeInstruction(
|
||||
uint64_t address, std::string_view inst_bytes, Instruction &inst) const {
|
||||
if (address % 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inst_bytes.size() != 4 && inst_bytes.size() != 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inst.pc = address;
|
||||
inst.next_pc = address + inst_bytes.size(); // Default fall-through.
|
||||
inst.branch_taken_pc = 0;
|
||||
inst.branch_not_taken_pc = 0;
|
||||
inst.has_branch_taken_delay_slot = false;
|
||||
inst.has_branch_not_taken_delay_slot = false;
|
||||
inst.arch_name = arch_name;
|
||||
inst.arch_for_decode = nullptr;
|
||||
inst.category = Instruction::kCategoryInvalid;
|
||||
inst.operands.clear();
|
||||
|
||||
if (!inst.bytes.empty() && inst.bytes.data() == inst_bytes.data()) {
|
||||
inst.bytes.resize(inst_bytes.size());
|
||||
} else {
|
||||
inst.bytes = inst_bytes;
|
||||
}
|
||||
|
||||
if (!sparc32::TryDecode(inst)) {
|
||||
inst.category = Instruction::kCategoryInvalid;
|
||||
inst.operands.clear();
|
||||
LOG(ERROR)
|
||||
<< "Unable to decode: " << inst.Serialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
// LOG(ERROR) << inst.Serialize();
|
||||
|
||||
return inst.IsValid();
|
||||
}
|
||||
|
||||
} // namespace sparc
|
||||
|
||||
// TODO(pag): We pretend that these are singletons, but they aren't really!
|
||||
Arch::ArchPtr Arch::GetSPARC(
|
||||
llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) {
|
||||
if (arch_name_ == kArchSparc32) {
|
||||
return std::make_unique<sparc::SPARC32Arch>(context_, os_name_, arch_name_);
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Invalid arch name passed to Arch::GetSPARC: "
|
||||
<< GetArchName(arch_name_);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace remill
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright (c) 2020 Trail of Bits, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_library(remill_arch_sparc32 STATIC
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Definitions.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/HyperCall.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Intrinsics.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Operators.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Runtime.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h"
|
||||
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/Types.h"
|
||||
|
||||
Arch.cpp
|
||||
Decode.h
|
||||
Extract.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(Runtime)
|
||||
|
||||
set_property(TARGET remill_arch_sparc32 PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_link_libraries(remill_arch_sparc32 LINK_PUBLIC
|
||||
remill_settings
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS remill_arch_sparc32
|
||||
ARCHIVE DESTINATION "${REMILL_INSTALL_LIB_DIR}"
|
||||
PUBLIC_HEADER DESTINATION "${REMILL_INSTALL_INCLUDE_DIR}"
|
||||
)
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
|
||||
namespace remill {
|
||||
namespace sparc {
|
||||
|
||||
union Format0a {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t imm22:22;
|
||||
uint32_t op2:3;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format0a) == 4, " ");
|
||||
|
||||
union Format0b {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
int32_t disp22:22;
|
||||
uint32_t op2:3;
|
||||
uint32_t cond:4;
|
||||
uint32_t a:1;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format0b) == 4, " ");
|
||||
|
||||
union Format0c {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
int32_t disp19:19;
|
||||
uint32_t p:1;
|
||||
uint32_t cc0:1;
|
||||
uint32_t cc1:1;
|
||||
uint32_t op2:3;
|
||||
uint32_t cond:4;
|
||||
uint32_t a:1;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format0c) == 4, " ");
|
||||
|
||||
union Format0d {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t d16lo:14;
|
||||
uint32_t rs1:5;
|
||||
uint32_t p:1;
|
||||
uint32_t d16hi:2;
|
||||
uint32_t op2:3;
|
||||
uint32_t rcond:3;
|
||||
uint32_t must_be_zero:1; // Bit 28.
|
||||
uint32_t a:1;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format0d) == 4, " ");
|
||||
|
||||
union Format3 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t ai0_ai1_b:14;
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3) == 4, " ");
|
||||
// SPARC Format 3a
|
||||
//_________________________________________________________________
|
||||
//| op| rd | op3 | rs1 |i| asi | rs2 |
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
union Format3ai0 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t asi:8;
|
||||
uint32_t i:1; // Must be 0.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3ai0) == 4, " ");
|
||||
|
||||
// SPARC Format 3a
|
||||
//_________________________________________________________________
|
||||
//| op| rd | op3 | rs1 |i| simm13 |
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
union Format3ai1 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
int32_t simm13:13;
|
||||
uint32_t i:1; // Must be 1.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
|
||||
// SPARC Format 3b
|
||||
//_________________________________________________________________
|
||||
//| op| rd | op3 | rs1 | opf | rs2 |
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
union Format3b {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t opf:9;
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2; // 3
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3b) == 4, " ");
|
||||
|
||||
union Format3c {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t opf:9;
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t cc0:1;
|
||||
uint32_t cc1:1;
|
||||
uint32_t _1:3;
|
||||
uint32_t op:2; // 3
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3b) == 4, " ");
|
||||
|
||||
union Format3di0 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t _1:5;
|
||||
uint32_t rcond:3;
|
||||
uint32_t i:1;
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2; // 3
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3di0) == 4, " ");
|
||||
|
||||
union Format3di1 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t simm10:10;
|
||||
uint32_t rcond:3;
|
||||
uint32_t i:1;
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2; // 3
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3di1) == 4, " ");
|
||||
|
||||
union Format3ei0 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t _1:7;
|
||||
uint32_t x:1;
|
||||
uint32_t i:1; // Must be 0.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3ei0) == 4, " ");
|
||||
|
||||
union Format3ei1 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t shcnt32:5;
|
||||
uint32_t _1:7;
|
||||
uint32_t x:1;
|
||||
uint32_t i:1; // Must be 0.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3ei1) == 4, " ");
|
||||
|
||||
union Format3ei2 {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t shcnt64:6;
|
||||
uint32_t _1:6;
|
||||
uint32_t x:1;
|
||||
uint32_t i:1; // Must be 0.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3ei2) == 4, " ");
|
||||
|
||||
union Format3f {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t mmask:4;
|
||||
uint32_t cmask:3;
|
||||
uint32_t _1:6;
|
||||
uint32_t i:1; // Must be 1.
|
||||
uint32_t bits:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t _2:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format3f) == 4, " ");
|
||||
|
||||
union Format4a {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t unused:6;
|
||||
uint32_t cc0:1;
|
||||
uint32_t cc1:1;
|
||||
uint32_t i:1; // 0.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format4a) == 4, " ");
|
||||
|
||||
union Format4b {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
int32_t simm11:11;
|
||||
uint32_t cc0:1;
|
||||
uint32_t cc1:1;
|
||||
uint32_t i:1; // 0.
|
||||
uint32_t rs1:5;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format4b) == 4, " ");
|
||||
|
||||
union Format4c {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
uint32_t rs2:5;
|
||||
uint32_t unused:6;
|
||||
uint32_t cc0:1;
|
||||
uint32_t cc1:1;
|
||||
uint32_t i:1; // 0.
|
||||
uint32_t cond:4;
|
||||
uint32_t cc2:1;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format4c) == 4, " ");
|
||||
|
||||
union Format4d {
|
||||
uint32_t flat;
|
||||
struct {
|
||||
int32_t simm11:11;
|
||||
uint32_t cc0:1;
|
||||
uint32_t cc1:1;
|
||||
uint32_t i:1; // 0.
|
||||
uint32_t cond:4;
|
||||
uint32_t cc2:1;
|
||||
uint32_t op3:6;
|
||||
uint32_t rd:5;
|
||||
uint32_t op:2;
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
static_assert(sizeof(Format4d) == 4, " ");
|
||||
|
||||
extern const std::string_view kCCRName[4];
|
||||
extern const std::string_view kFCCRName[8];
|
||||
extern const std::string_view kReadIntRegName[32];
|
||||
extern const std::string_view kWriteIntRegName[32];
|
||||
extern const std::string_view kCondName[16];
|
||||
extern const std::string_view kFCondName[16];
|
||||
extern const std::string_view kRCondName[8];
|
||||
|
||||
void AddSrcRegop(Instruction &inst, const char *reg_name, unsigned size);
|
||||
void AddDestRegop(Instruction &inst, const char *reg_name, unsigned size);
|
||||
void AddImmop(Instruction &inst, uint64_t imm,
|
||||
unsigned size, bool is_signed);
|
||||
|
||||
} // namespace sparc
|
||||
|
||||
namespace sparc32 {
|
||||
|
||||
bool TryDecode(Instruction &inst);
|
||||
|
||||
} // namespace sparc32
|
||||
} // namespace remill
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
|
||||
#include "remill/Arch/Runtime/Float.h"
|
||||
#include "remill/Arch/SPARC32/Runtime/State.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Instructions will be lifted into clones of this function.
|
||||
[[gnu::used]] Memory *__remill_basic_block(State &, addr_t, Memory *);
|
||||
|
||||
} // extern C
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2019 Trail of Bits, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(sparc32_runtime)
|
||||
|
||||
set(SPARC32RUNTIME_SOURCEFILES
|
||||
Instructions.cpp
|
||||
BasicBlock.cpp
|
||||
|
||||
"${REMILL_LIB_DIR}/Arch/Runtime/Intrinsics.cpp"
|
||||
)
|
||||
|
||||
set_source_files_properties(Instructions.cpp PROPERTIES COMPILE_FLAGS "-O3 -g0")
|
||||
set_source_files_properties(BasicBlock.cpp PROPERTIES COMPILE_FLAGS "-O0 -g3")
|
||||
|
||||
if (REMILL_BARRIER_AS_NOP)
|
||||
set(EXTRA_BC_FLAGS "-DREMILL_BARRIER_AS_NOP")
|
||||
endif(REMILL_BARRIER_AS_NOP)
|
||||
|
||||
function(add_runtime_helper target_name little_endian)
|
||||
message(" > Generating runtime target: ${target_name}")
|
||||
|
||||
add_runtime(${target_name}
|
||||
SOURCES ${SPARC32RUNTIME_SOURCEFILES}
|
||||
ADDRESS_SIZE 32
|
||||
DEFINITIONS "LITTLE_ENDIAN=${little_endian}"
|
||||
BCFLAGS "-m32" "-std=c++17" "${EXTRA_BC_FLAGS}"
|
||||
INCLUDEDIRECTORIES "${REMILL_INCLUDE_DIR}" "${REMILL_SOURCE_DIR}"
|
||||
INSTALLDESTINATION "${REMILL_INSTALL_SEMANTICS_DIR}"
|
||||
|
||||
DEPENDENCIES
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Float.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Types.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Operators.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Intrinsics.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/HyperCall.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/Runtime/Definitions.h"
|
||||
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/State.h"
|
||||
"${REMILL_INCLUDE_DIR}/remill/Arch/SPARC32/Runtime/Types.h"
|
||||
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/COND.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/BINARY.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/BRANCH.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/DATAXFER.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/FLAGS.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/FOP.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/LOGICAL.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/MISC.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/TRAP.cpp"
|
||||
"${REMILL_LIB_DIR}/Arch/SPARC32/Semantics/WINDOW.cpp"
|
||||
|
||||
"${REMILL_LIB_DIR}/Arch/Runtime/Intrinsics.cpp"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
add_runtime_helper(sparc32 0)
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Trail of Bits, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
|
||||
#include "remill/Arch/Runtime/Float.h"
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
#include "remill/Arch/SPARC32/Runtime/State.h"
|
||||
#include "remill/Arch/SPARC32/Runtime/Types.h"
|
||||
|
||||
#define REG_PC state.pc.aword
|
||||
#define REG_NPC state.next_pc.aword
|
||||
#define REG_SP state.gpr.o6.aword
|
||||
#define REG_FP state.gpr.i6.aword
|
||||
|
||||
#define REG_G0 state.gpr.g0.aword
|
||||
#define REG_G1 state.gpr.g1.aword
|
||||
#define REG_G7 state.gpr.g7.aword // Thread local pointer
|
||||
|
||||
#define REG_L0 state.gpr.l0.aword
|
||||
#define REG_L1 state.gpr.l1.aword
|
||||
#define REG_L2 state.gpr.l2.aword
|
||||
#define REG_L3 state.gpr.l3.aword
|
||||
#define REG_L4 state.gpr.l4.aword
|
||||
#define REG_L5 state.gpr.l5.aword
|
||||
#define REG_L6 state.gpr.l6.aword
|
||||
#define REG_L7 state.gpr.l7.aword
|
||||
|
||||
#define REG_I0 state.gpr.i0.aword
|
||||
#define REG_I1 state.gpr.i1.aword
|
||||
#define REG_I2 state.gpr.i2.aword
|
||||
#define REG_I3 state.gpr.i3.aword
|
||||
#define REG_I4 state.gpr.i4.aword
|
||||
#define REG_I5 state.gpr.i5.aword
|
||||
#define REG_I6 state.gpr.i6.aword
|
||||
#define REG_I7 state.gpr.i7.aword
|
||||
|
||||
#define REG_O0 state.gpr.o0.aword
|
||||
#define REG_O1 state.gpr.o1.aword
|
||||
#define REG_O2 state.gpr.o2.aword
|
||||
#define REG_O3 state.gpr.o3.aword
|
||||
#define REG_O4 state.gpr.o4.aword
|
||||
#define REG_O5 state.gpr.o5.aword
|
||||
#define REG_O6 state.gpr.o6.aword
|
||||
#define REG_O7 state.gpr.o7.aword
|
||||
|
||||
#define REG_F0 state.fpreg.v[0].floats.elems[0]
|
||||
#define REG_F1 state.fpreg.v[0].floats.elems[1]
|
||||
#define REG_F2 state.fpreg.v[0].floats.elems[2]
|
||||
#define REG_F3 state.fpreg.v[0].floats.elems[3]
|
||||
|
||||
#define REG_D0 state.fpreg.v[0].qwords.elems[0]
|
||||
|
||||
// GSR Register
|
||||
#define GSR_ALIGN state.asr.gsr.align
|
||||
#define GSR_MASK state.asr.gsr.mask
|
||||
|
||||
#define REG_Y state.asr.yreg.aword
|
||||
|
||||
#define FLAG_ICC_CF state.asr.ccr.icc.c
|
||||
#define FLAG_ICC_VF state.asr.ccr.icc.v
|
||||
#define FLAG_ICC_ZF state.asr.ccr.icc.z
|
||||
#define FLAG_ICC_NF state.asr.ccr.icc.n
|
||||
|
||||
#define FLAG_XCC_CF state.asr.ccr.xcc.c
|
||||
#define FLAG_XCC_VF state.asr.ccr.xcc.v
|
||||
#define FLAG_XCC_ZF state.asr.ccr.xcc.z
|
||||
#define FLAG_XCC_NF state.asr.ccr.xcc.n
|
||||
|
||||
#define REG_ICC state.asr.ccr.icc.flat
|
||||
#define REG_XCC state.asr.ccr.xcc.flat
|
||||
#define REG_CCC state.csr.ccc
|
||||
|
||||
#define FSR_FCC0 state.fsr.fcc0
|
||||
#define FSR_FCC1 state.fsr.fcc1
|
||||
#define FSR_FCC2 state.fsr.fcc2
|
||||
#define FSR_FCC3 state.fsr.fcc3
|
||||
|
||||
#define FSR_CEXC state.fsr.cexc
|
||||
#define FSR_FTT state.fsr.ftt
|
||||
#define FSR_RD state.fsr.rd
|
||||
|
||||
#define PSR_TPC state.psr.tpc
|
||||
#define PSR_TNPC state.psr.tnpc
|
||||
#define PSR_TSTATE state.psr.tstate
|
||||
#define PSR_TT state.psr.tt
|
||||
#define PSR_TBA state.psr.tba
|
||||
#define PSR_PSTATE state.psr.pstate
|
||||
#define PSR_TL state.psr.tl
|
||||
#define PSR_PIL state.psr.pil
|
||||
#define PSR_WSTATE state.psr.wstate
|
||||
#define PSR_CWP state.psr.cwp
|
||||
#define PSR_CANSAVE state.psr.cansave
|
||||
#define PSR_CANRESTORE state.psr.canrestore
|
||||
#define PSR_CLEANWIN state.psr.cleanwin
|
||||
#define PSR_OTHERWIN state.psr.otherwin
|
||||
#define PSR_GL state.psr.gl
|
||||
|
||||
#define ASR_Y state.asr.yreg.dword
|
||||
#define ASR_ASI state.asr.asi_flat
|
||||
#define ASR_PC state.pc.aword
|
||||
#define ASR_FPRS state.asr.fprs_flat
|
||||
#define ASR_GSR state.asr.gsr.flat
|
||||
#define ASR_SOFTINT state.asr.softint
|
||||
#define ASR_STICK_CMPR state.asr.stick_cmpr
|
||||
#define ASR_PAUSE state.asr.pause
|
||||
|
||||
#define HYPER_CALL state.hyper_call
|
||||
#define INTERRUPT_VECTOR state.hyper_call_vector
|
||||
#define HYPER_CALL_VECTOR state.hyper_call_vector
|
||||
|
||||
#if ADDRESS_SIZE_BITS == 64
|
||||
# define SPARC_STACKBIAS 0
|
||||
#else
|
||||
# define SPARC_STACKBIAS 0
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// Takes the place of an unsupported instruction.
|
||||
DEF_SEM(HandleUnsupported) {
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::IF_32BIT_ELSE(kSPARC32EmulateInstruction, kSPARC64EmulateInstruction));
|
||||
}
|
||||
|
||||
// Takes the place of an invalid instruction.
|
||||
DEF_SEM(HandleInvalidInstruction) {
|
||||
HYPER_CALL = AsyncHyperCall::kInvalidInstruction;
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_HELPER(SAVE_WINDOW, RegisterWindow *window, RegisterWindow *&prev_window) -> void {
|
||||
|
||||
// TODO(pag): These two lines should be uncommented for correctness, but then
|
||||
// they don't result in as nice bitcode in McSema :-(
|
||||
// window->prev_window = state.window;
|
||||
// state.window = window;
|
||||
|
||||
prev_window = window;
|
||||
|
||||
window->l0 = Read(REG_L0);
|
||||
window->l1 = Read(REG_L1);
|
||||
window->l2 = Read(REG_L2);
|
||||
window->l3 = Read(REG_L3);
|
||||
window->l4 = Read(REG_L4);
|
||||
window->l5 = Read(REG_L5);
|
||||
window->l6 = Read(REG_L6);
|
||||
window->l7 = Read(REG_L7);
|
||||
|
||||
window->i0 = Read(REG_I0);
|
||||
window->i1 = Read(REG_I1);
|
||||
window->i2 = Read(REG_I2);
|
||||
window->i3 = Read(REG_I3);
|
||||
window->i4 = Read(REG_I4);
|
||||
window->i5 = Read(REG_I5);
|
||||
window->i6 = Read(REG_I6);
|
||||
window->i7 = Read(REG_I7);
|
||||
|
||||
// Move output register to input
|
||||
Write(REG_I0, REG_O0);
|
||||
Write(REG_I1, REG_O1);
|
||||
Write(REG_I2, REG_O2);
|
||||
Write(REG_I3, REG_O3);
|
||||
Write(REG_I4, REG_O4);
|
||||
Write(REG_I5, REG_O5);
|
||||
Write(REG_I6, REG_O6);
|
||||
Write(REG_I7, REG_O7);
|
||||
}
|
||||
|
||||
DEF_HELPER(RESTORE_WINDOW, RegisterWindow *&prev_window) -> void {
|
||||
|
||||
const auto window = prev_window ? prev_window : state.window;
|
||||
if (!window) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kSPARCWindowUnderflow);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(pag): This next line should be uncommented for correctness, but then
|
||||
// it means not as nice bitcode for mcsema.
|
||||
// state.window = window->prev_window;
|
||||
|
||||
// Move input register to output
|
||||
Write(REG_O0, REG_I0);
|
||||
Write(REG_O1, REG_I1);
|
||||
Write(REG_O2, REG_I2);
|
||||
Write(REG_O3, REG_I3);
|
||||
Write(REG_O4, REG_I4);
|
||||
Write(REG_O5, REG_I5);
|
||||
Write(REG_O6, REG_I6);
|
||||
Write(REG_O7, REG_I7);
|
||||
|
||||
Write(REG_L0, window->l0);
|
||||
Write(REG_L1, window->l1);
|
||||
Write(REG_L2, window->l2);
|
||||
Write(REG_L3, window->l3);
|
||||
Write(REG_L4, window->l4);
|
||||
Write(REG_L5, window->l5);
|
||||
Write(REG_L6, window->l6);
|
||||
Write(REG_L7, window->l7);
|
||||
|
||||
Write(REG_I0, window->i0);
|
||||
Write(REG_I1, window->i1);
|
||||
Write(REG_I2, window->i2);
|
||||
Write(REG_I3, window->i3);
|
||||
Write(REG_I4, window->i4);
|
||||
Write(REG_I5, window->i5);
|
||||
Write(REG_I6, window->i6);
|
||||
Write(REG_I7, window->i7);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Takes the place of an unsupported instruction.
|
||||
DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported;
|
||||
DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction;
|
||||
|
||||
#include "lib/Arch/SPARC32/Semantics/FLAGS.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/COND.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/BINARY.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/BRANCH.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/DATAXFER.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/FOP.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/LOGICAL.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/MISC.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/TRAP.cpp"
|
||||
#include "lib/Arch/SPARC32/Semantics/WINDOW.cpp"
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Tag, typename T>
|
||||
ALWAYS_INLINE static void WriteFlagsIncDec(State &state, T lhs, T rhs, T res) {
|
||||
FLAG_ICC_ZF = ZeroFlag(res);
|
||||
FLAG_ICC_NF = SignFlag(res);
|
||||
FLAG_ICC_VF = Overflow<Tag>::Flag(lhs, rhs, res);
|
||||
}
|
||||
|
||||
template <typename Tag, typename T>
|
||||
ALWAYS_INLINE static void WriteFlagsAddSub(State &state, T lhs, T rhs, T res) {
|
||||
FLAG_ICC_CF = Carry<Tag>::Flag(lhs, rhs, res);
|
||||
WriteFlagsIncDec<Tag>(state, lhs, rhs, res);
|
||||
}
|
||||
|
||||
template <typename Tag, typename T>
|
||||
ALWAYS_INLINE static void WriteXCCFlagsIncDec(State &state, T lhs, T rhs, T res) {
|
||||
FLAG_XCC_ZF = ZeroFlag(res);
|
||||
FLAG_XCC_NF = SignFlag(res);
|
||||
FLAG_XCC_VF = Overflow<Tag>::Flag(lhs, rhs, res);
|
||||
}
|
||||
|
||||
template <typename Tag, typename T>
|
||||
ALWAYS_INLINE static void WriteICCFlagsIncDec(State &state, T lhs, T rhs, T res) {
|
||||
FLAG_ICC_ZF = ZeroFlag(res);
|
||||
FLAG_ICC_NF = SignFlag(res);
|
||||
FLAG_ICC_VF = Overflow<Tag>::Flag(lhs, rhs, res);
|
||||
}
|
||||
|
||||
template <typename Tag>
|
||||
ALWAYS_INLINE static void WriteICCFlagsAddSub(State &state, uint32_t lhs, uint32_t rhs, uint32_t res) {
|
||||
FLAG_ICC_CF = Carry<Tag>::Flag(lhs, rhs, res);
|
||||
WriteICCFlagsIncDec<Tag>(state, lhs, rhs, res);
|
||||
}
|
||||
|
||||
template <typename Tag>
|
||||
ALWAYS_INLINE static void WriteXCCFlagsAddSub(State &state, uint64_t lhs, uint64_t rhs, uint64_t res) {
|
||||
FLAG_XCC_CF = Carry<Tag>::Flag(lhs, rhs, res);
|
||||
WriteXCCFlagsIncDec<Tag>(state, lhs, rhs, res);
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SUB, S1 src1, S2 src2, D dst) {
|
||||
Write(dst, USub(Read(src1), Read(src2)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SUBcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto res = USub(lhs, rhs);
|
||||
Write(dst, res);
|
||||
WriteICCFlagsAddSub<tag_sub>(state, lhs, rhs, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SUBX, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto carry = ZExtTo<S1>(Unsigned(Read(FLAG_ICC_CF)));
|
||||
auto sub = USub(lhs, rhs);
|
||||
auto res = USub(sub, carry);
|
||||
Write(dst, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SUBXcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto carry = ZExtTo<S1>(Unsigned(Read(FLAG_ICC_CF)));
|
||||
auto sub = USub(lhs, rhs);
|
||||
auto res = USub(sub, carry);
|
||||
WriteZExt(dst, res);
|
||||
WriteICCFlagsAddSub<tag_sub>(state, lhs, rhs, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(ADD, S1 src1, S2 src2, D dst) {
|
||||
Write(dst, UAdd(Read(src1), Read(src2)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(ADDcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto res = UAdd(lhs, rhs);
|
||||
Write(dst, res);
|
||||
WriteICCFlagsAddSub<tag_add>(state, lhs, rhs, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(ADDX, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto carry = ZExtTo<S1>(Unsigned(Read(FLAG_ICC_CF)));
|
||||
auto sum = UAdd(lhs, rhs);
|
||||
auto res = UAdd(sum, carry);
|
||||
Write(dst, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(ADDXcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto carry = ZExtTo<S1>(Unsigned(Read(FLAG_ICC_CF)));
|
||||
auto sum = UAdd(lhs, rhs);
|
||||
auto res = UAdd(sum, carry);
|
||||
Write(dst, res);
|
||||
WriteICCFlagsAddSub<tag_add>(state, lhs, rhs, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SMUL, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Signed(Read(src1));
|
||||
auto rhs = Signed(Read(src2));
|
||||
auto lhs_wide = SExt(lhs);
|
||||
auto rhs_wide = SExt(rhs);
|
||||
auto res = SMul(lhs_wide, rhs_wide);
|
||||
auto res_trunc = TruncTo<S1>(res);
|
||||
WriteZExt(dst, res_trunc);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SMULcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Signed(Read(src1));
|
||||
auto rhs = Signed(Read(src2));
|
||||
auto lhs_wide = SExt(lhs);
|
||||
auto rhs_wide = SExt(rhs);
|
||||
auto res = SMul(lhs_wide, rhs_wide);
|
||||
auto res_trunc = TruncTo<S1>(res);
|
||||
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(res));
|
||||
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(res));
|
||||
FLAG_ICC_VF = 0;
|
||||
FLAG_ICC_CF = 0;
|
||||
auto index = Literal<S1>(32);
|
||||
auto y_val = UShr(decltype(index)(res), index);
|
||||
Write(ASR_Y, y_val);
|
||||
WriteZExt(dst, res_trunc);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(UMUL, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto rhs_wide = ZExt(rhs);
|
||||
auto res = UMul(lhs_wide, rhs_wide);
|
||||
auto res_trunc = TruncTo<S1>(res);
|
||||
WriteZExt(dst, res_trunc);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(UMULcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto rhs_wide = ZExt(rhs);
|
||||
auto res = UMul(lhs_wide, rhs_wide);
|
||||
auto res_trunc = TruncTo<S1>(res);
|
||||
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(res));
|
||||
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(res));
|
||||
FLAG_ICC_VF = 0;
|
||||
FLAG_ICC_CF = 0;
|
||||
auto index = Literal<S1>(32);
|
||||
auto y_val = UShr(decltype(index)(res), index);
|
||||
Write(ASR_Y, y_val);
|
||||
WriteZExt(dst, res_trunc);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(MULX, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto rhs_wide = ZExt(rhs);
|
||||
auto res = UMul(lhs_wide, rhs_wide);
|
||||
auto res_trunc = TruncTo<S1>(res);
|
||||
WriteZExt(dst, res_trunc);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SDIV, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto y = Read(REG_Y);
|
||||
auto y_lhs_wide = Signed(UOr(decltype(lhs_wide)(
|
||||
UShl(y, Literal<decltype(y)>(32))), lhs_wide));
|
||||
auto rhs = Signed(Read(src2));
|
||||
auto rhs_wide = SExt(rhs);
|
||||
auto quot = SDiv(y_lhs_wide, rhs_wide);
|
||||
WriteTrunc(dst, quot);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SDIVcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto y = Read(REG_Y);
|
||||
auto y_lhs_wide = Signed(UOr(decltype(lhs_wide)(
|
||||
UShl(y, Literal<decltype(y)>(32))), lhs_wide));
|
||||
auto rhs = Read(src2);
|
||||
auto rhs_wide = SExt(rhs);
|
||||
auto quot = SDiv(y_lhs_wide, rhs_wide);
|
||||
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(quot));
|
||||
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(quot));
|
||||
FLAG_ICC_VF = Overflow<tag_sdiv>::Flag(lhs, rhs, quot);
|
||||
FLAG_ICC_CF = 0;
|
||||
auto res = Overflow<tag_sdiv>::Value(lhs, rhs, quot);
|
||||
WriteTrunc(dst, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(UDIV, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto rhs_wide = ZExt(rhs);
|
||||
auto quot = UDiv(lhs_wide, rhs_wide);
|
||||
WriteTrunc(dst, quot);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(UDIVcc, S1 src1, S2 src2, D dst) {
|
||||
auto lhs = Read(src1);
|
||||
auto rhs = Read(src2);
|
||||
auto lhs_wide = ZExt(lhs);
|
||||
auto rhs_wide = ZExt(rhs);
|
||||
auto quot = UDiv(lhs_wide, rhs_wide);
|
||||
FLAG_ICC_NF = SignFlag(static_cast<uint32_t>(quot));
|
||||
FLAG_ICC_ZF = ZeroFlag(static_cast<uint32_t>(quot));
|
||||
FLAG_ICC_VF = Overflow<tag_udiv>::Flag(lhs, rhs, quot);
|
||||
FLAG_ICC_CF = 0;
|
||||
auto res = Overflow<tag_udiv>::Value(lhs, rhs, quot);
|
||||
WriteTrunc(dst, res);
|
||||
return memory;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEF_ISEL(SUB) = SUB<R32, R32, R32W>;
|
||||
DEF_ISEL(SUBcc) = SUBcc<R32, R32, R32W>;
|
||||
DEF_ISEL(SUBX) = SUBX<R32, R32, R32W>;
|
||||
DEF_ISEL(SUBXcc) = SUBXcc<R32, R32, R32W>;
|
||||
|
||||
DEF_ISEL(ADD) = ADD<R32, R32, R32W>;
|
||||
DEF_ISEL(ADDcc) = ADDcc<R32, R32, R32W>;
|
||||
DEF_ISEL(ADDX) = ADDX<R32, R32, R32W>;
|
||||
DEF_ISEL(ADDXcc) = ADDXcc<R32, R32, R32W>;
|
||||
|
||||
DEF_ISEL(SMUL) = SMUL<R32, R32, R32W>;
|
||||
DEF_ISEL(SMULcc) = SMULcc<R32, R32, R32W>;
|
||||
DEF_ISEL(UMUL) = UMUL<R32, R32, R32W>;
|
||||
DEF_ISEL(UMULcc) = UMULcc<R32, R32, R32W>;
|
||||
DEF_ISEL(MULX) = MULX<R32, R32, R32W>;
|
||||
|
||||
DEF_ISEL(SDIV) = SDIV<R32, R32, R32W>;
|
||||
DEF_ISEL(SDIVcc) = SDIVcc<R32, R32, R32W>;
|
||||
DEF_ISEL(UDIV) = UDIV<R32, R32, R32W>;
|
||||
DEF_ISEL(UDIVcc) = UDIVcc<R32, R32, R32W>;
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(MULSCC_R32, R32 src1, R32 src2, R32W dest) {
|
||||
auto rs1 = Read(src1);
|
||||
auto rs2 = Read(src2);
|
||||
auto y = Read(REG_Y);
|
||||
auto lsb_y = UAnd(y, Literal<decltype(y)>(0x1));
|
||||
auto masked_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0xffffffff));
|
||||
auto masked_rs2 = UAnd(rs2, Literal<decltype(rs2)>(0xffffffff));
|
||||
auto new_rs2 = Select(UCmpEq(lsb_y, 0), Literal<decltype(rs2)>(0), masked_rs2);
|
||||
|
||||
auto flag_nf = Literal<uint32_t>(Read(FLAG_ICC_NF));
|
||||
auto flag_vf = Literal<uint32_t>(Read(FLAG_ICC_VF));
|
||||
auto nxorv = UXor(flag_nf, flag_vf);
|
||||
auto shifted_flag = UShl(nxorv, Literal<decltype(nxorv)>(31));
|
||||
auto new_rs1 = UOr(UShr(masked_rs1, Literal<decltype(masked_rs1)>(1)),
|
||||
Literal<decltype(masked_rs1)>(shifted_flag));
|
||||
auto res = UAdd(new_rs1, new_rs2);
|
||||
// Y register is shifted right by one bit, with the LSB of the unshifted
|
||||
// r[rs1] replacing the MSB of Y
|
||||
auto shifted_y = UShr(y, Literal<decltype(y)>(1));
|
||||
auto lsb_rs1 = UAnd(rs1, Literal<decltype(rs1)>(0x1));
|
||||
auto new_y = UOr(shifted_y, decltype(y)(UShl(lsb_rs1, Literal<decltype(lsb_rs1)>(31))));
|
||||
Write(REG_Y, new_y);
|
||||
Write(dest, res);
|
||||
|
||||
|
||||
WriteICCFlagsAddSub<tag_add>(
|
||||
state, static_cast<uint32_t>(new_rs1),
|
||||
static_cast<uint32_t>(new_rs2), static_cast<uint32_t>(res));
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEF_ISEL(MULScc) = MULSCC_R32;
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
// NOTE(pag): `new_pc == pc_of_jmp + 4`, and `new_npc`
|
||||
// is the target EA.
|
||||
template <typename T>
|
||||
DEF_SEM(JMPL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst,
|
||||
T dst_pc, T dst_npc) {
|
||||
auto new_dst = Read(pc_of_jmp);
|
||||
auto new_dst_pc = Read(new_pc);
|
||||
auto new_dst_npc = Read(new_npc);
|
||||
Write(dst, new_dst);
|
||||
Write(dst_pc, new_dst_pc);
|
||||
Write(dst_npc, new_dst_npc);
|
||||
return memory;
|
||||
}
|
||||
|
||||
// This is a variation on JMPL that also stores the return address.
|
||||
template <typename T>
|
||||
DEF_SEM(CALL, PC pc_of_jmp, PC new_pc, PC new_npc, T dst,
|
||||
T dst_pc, T dst_npc, T return_pc_dst) {
|
||||
Write(dst, Read(pc_of_jmp));
|
||||
Write(dst_pc, Read(new_pc));
|
||||
Write(dst_npc, Read(new_npc));
|
||||
|
||||
// NOTE(pag): See comment above about conventions.
|
||||
Write(return_pc_dst, UAdd(Read(pc_of_jmp), 8));
|
||||
return memory;
|
||||
}
|
||||
|
||||
// Makes an asynchronous and synchronous version of the trap. The asynchronous
|
||||
// exists during normal control-flow, and introduces its own control flow and
|
||||
// an async hyper call. The synchronous version exists when the trap instruction
|
||||
// is placed inside of a delay slot.
|
||||
#define MAKE_BRANCH(name, cond, cc) \
|
||||
namespace { \
|
||||
DEF_SEM(name ## cond ## _ ## cc, R8W branch_taken, PC new_taken_pc, PC new_taken_npc, \
|
||||
PC new_not_taken_pc, PC new_not_taken_npc, \
|
||||
R32W pc_dst, R32W npc_dst) { \
|
||||
if (Cond ## cond ## _ ## cc(state)) { \
|
||||
Write(branch_taken, true); \
|
||||
Write(pc_dst, Read(new_taken_pc)); \
|
||||
Write(npc_dst, Read(new_taken_npc)); \
|
||||
} else { \
|
||||
Write(branch_taken, false); \
|
||||
Write(pc_dst, Read(new_not_taken_pc)); \
|
||||
Write(npc_dst, Read(new_not_taken_npc)); \
|
||||
} \
|
||||
return memory; \
|
||||
} \
|
||||
} \
|
||||
DEF_ISEL(name ## cond ## _ ## cc) = name ## cond ## _ ## cc;
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(BA, PC new_taken_pc, PC new_taken_npc,
|
||||
T pc_dst, T npc_dst) {
|
||||
Write(pc_dst, Read(new_taken_pc));
|
||||
Write(npc_dst, Read(new_taken_npc));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(BN, PC new_not_taken_pc, PC new_not_taken_npc,
|
||||
T pc_dst, T npc_dst) {
|
||||
Write(pc_dst, Read(new_not_taken_pc));
|
||||
Write(npc_dst, Read(new_not_taken_npc));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(FBA, PC new_taken_pc, PC new_taken_npc,
|
||||
T pc_dst, T npc_dst) {
|
||||
Write(pc_dst, Read(new_taken_pc));
|
||||
Write(npc_dst, Read(new_taken_npc));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(FBN, PC new_not_taken_pc, PC new_not_taken_npc,
|
||||
T pc_dst, T npc_dst) {
|
||||
Write(pc_dst, Read(new_not_taken_pc));
|
||||
Write(npc_dst, Read(new_not_taken_npc));
|
||||
return memory;
|
||||
}
|
||||
|
||||
// A branch instruction existing in a delay slot. These are DCTI couples. They
|
||||
// have weird pipeline effects, e.g.
|
||||
//
|
||||
// address instruction target
|
||||
// ------------+------------------+--------------
|
||||
// 8 not-a-cti
|
||||
// 12 cti 40
|
||||
// 16 cti 60
|
||||
// 20 not-a-cti
|
||||
// 24 ...
|
||||
//
|
||||
// 40 not-a-cti
|
||||
// 44 ...
|
||||
//
|
||||
// 60 not-a-cti
|
||||
// 64 ...
|
||||
//
|
||||
// case 12: cti 40 16: cti 60 order of execution
|
||||
// -----+---------------------+-----------------+---------------------
|
||||
// 1 dcti unconditional dcti taken 12,16,40,60,64,...
|
||||
// 2 dcti unconditional B*cc(a=0) untaken 12,16,40,44
|
||||
// 3 dcti unconditional B*cc(a=1) untaken 12,16,44,48 (40 annulled)
|
||||
// 4 dcti unconditional B*A(a=1) 12,16,60,64 (40 annulled)
|
||||
// 5 B*A(a=1) any cti 12,40,44,... (16 annulled)
|
||||
// 6 B*cc dcti 12,unpredictable
|
||||
DEF_SEM(UNSUPPORTED_DCTI) {
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kSPARCUnhandledDCTI);
|
||||
}
|
||||
|
||||
// TODO(pag): Double check that `new_pc` reads `rs1/rs2` from the pre-
|
||||
// incremented register window state.
|
||||
template <typename T>
|
||||
DEF_SEM(RETT, PC new_pc, PC new_npc, T dst_pc, T dst_npc,
|
||||
RegisterWindow *&prev_window) {
|
||||
RESTORE_WINDOW(memory, state, prev_window);
|
||||
Write(dst_pc, Read(new_pc));
|
||||
Write(dst_npc, Read(new_npc));
|
||||
return memory;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEF_ISEL(UNSUPPORTED_DCTI) = UNSUPPORTED_DCTI;
|
||||
|
||||
DEF_ISEL(CALL) = CALL<R32W>;
|
||||
DEF_ISEL(CALL_INDIRECT) = CALL<R32W>;
|
||||
DEF_ISEL(JMPL) = JMPL<R32W>;
|
||||
DEF_ISEL(RETL) = JMPL<R32W>;
|
||||
DEF_ISEL(RETT) = RETT<R32W>;
|
||||
|
||||
DEF_ISEL(BA_icc) = BA<R32W>;
|
||||
DEF_ISEL(BN_icc) = BN<R32W>;
|
||||
|
||||
DEF_ISEL(BA_xcc) = BA<R32W>;
|
||||
DEF_ISEL(BN_xcc) = BN<R32W>;
|
||||
|
||||
DEF_ISEL(FBA_fcc0) = FBA<R32W>;
|
||||
DEF_ISEL(FBA_fcc1) = FBA<R32W>;
|
||||
DEF_ISEL(FBA_fcc2) = FBA<R32W>;
|
||||
DEF_ISEL(FBA_fcc3) = FBA<R32W>;
|
||||
|
||||
DEF_ISEL(FBN_fcc0) = FBN<R32W>;
|
||||
DEF_ISEL(FBN_fcc1) = FBN<R32W>;
|
||||
DEF_ISEL(FBN_fcc2) = FBN<R32W>;
|
||||
DEF_ISEL(FBN_fcc3) = FBN<R32W>;
|
||||
|
||||
#define MAKE_BRANCH_CC(name, cond) \
|
||||
MAKE_BRANCH(name, cond, icc) \
|
||||
MAKE_BRANCH(name, cond, xcc) \
|
||||
|
||||
MAKE_BRANCH_CC(B, NE)
|
||||
MAKE_BRANCH_CC(B, E)
|
||||
MAKE_BRANCH_CC(B, G)
|
||||
MAKE_BRANCH_CC(B, LE)
|
||||
MAKE_BRANCH_CC(B, GE)
|
||||
MAKE_BRANCH_CC(B, L)
|
||||
MAKE_BRANCH_CC(B, GU)
|
||||
MAKE_BRANCH_CC(B, LEU)
|
||||
MAKE_BRANCH_CC(B, CC)
|
||||
MAKE_BRANCH_CC(B, CS)
|
||||
MAKE_BRANCH_CC(B, POS)
|
||||
MAKE_BRANCH_CC(B, NEG)
|
||||
MAKE_BRANCH_CC(B, VC)
|
||||
MAKE_BRANCH_CC(B, VS)
|
||||
|
||||
#define MAKE_BRANCH_F(name, cond) \
|
||||
MAKE_BRANCH(name, cond, fcc0) \
|
||||
MAKE_BRANCH(name, cond, fcc1) \
|
||||
MAKE_BRANCH(name, cond, fcc2) \
|
||||
MAKE_BRANCH(name, cond, fcc3)
|
||||
|
||||
MAKE_BRANCH_F(FB, U)
|
||||
MAKE_BRANCH_F(FB, G)
|
||||
MAKE_BRANCH_F(FB, UG)
|
||||
MAKE_BRANCH_F(FB, L)
|
||||
MAKE_BRANCH_F(FB, UL)
|
||||
MAKE_BRANCH_F(FB, LG)
|
||||
MAKE_BRANCH_F(FB, NE)
|
||||
MAKE_BRANCH_F(FB, E)
|
||||
MAKE_BRANCH_F(FB, UE)
|
||||
MAKE_BRANCH_F(FB, GE)
|
||||
MAKE_BRANCH_F(FB, UGE)
|
||||
MAKE_BRANCH_F(FB, LE)
|
||||
MAKE_BRANCH_F(FB, ULE)
|
||||
MAKE_BRANCH_F(FB, O)
|
||||
|
||||
|
||||
#undef MAKE_BRANCH
|
||||
#undef MAKE_BRANCH_F
|
||||
|
||||
|
||||
// Branch on Coprocessor Condition Codes Instructions
|
||||
|
||||
#define MAKE_BRANCH(name, cond) \
|
||||
namespace { \
|
||||
DEF_SEM(name ## cond, R8W branch_taken, PC new_taken_pc, PC new_taken_npc, \
|
||||
PC new_not_taken_pc, PC new_not_taken_npc, \
|
||||
R32W pc_dst, R32W npc_dst) { \
|
||||
if (Cond ## cond ## _ccc(state)) { \
|
||||
Write(branch_taken, true); \
|
||||
Write(pc_dst, Read(new_taken_pc)); \
|
||||
Write(npc_dst, Read(new_taken_npc)); \
|
||||
} else { \
|
||||
Write(branch_taken, false); \
|
||||
Write(pc_dst, Read(new_not_taken_pc)); \
|
||||
Write(npc_dst, Read(new_not_taken_npc)); \
|
||||
} \
|
||||
return memory; \
|
||||
} \
|
||||
} \
|
||||
DEF_ISEL(name ## cond) = name ## cond;
|
||||
|
||||
MAKE_BRANCH(CB, A)
|
||||
MAKE_BRANCH(CB, N)
|
||||
MAKE_BRANCH(CB, 3)
|
||||
MAKE_BRANCH(CB, 2)
|
||||
MAKE_BRANCH(CB, 23)
|
||||
MAKE_BRANCH(CB, 1)
|
||||
MAKE_BRANCH(CB, 13)
|
||||
MAKE_BRANCH(CB, 12)
|
||||
MAKE_BRANCH(CB, 123)
|
||||
MAKE_BRANCH(CB, 0)
|
||||
MAKE_BRANCH(CB, 03)
|
||||
MAKE_BRANCH(CB, 02)
|
||||
MAKE_BRANCH(CB, 023)
|
||||
MAKE_BRANCH(CB, 01)
|
||||
MAKE_BRANCH(CB, 013)
|
||||
MAKE_BRANCH(CB, 012)
|
||||
|
||||
#undef MAKE_BRANCH
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*/
|
||||
|
||||
#define MAKE_CONDITIONS(cc) \
|
||||
static inline bool \
|
||||
CondA_ ## cc(const State &state) { \
|
||||
return true; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondN_ ## cc(const State &state) { \
|
||||
return false; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondE_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_zf = ccr.z; \
|
||||
return flag_zf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondNE_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_zf = ccr.z; \
|
||||
return !flag_zf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondG_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_nf = ccr.n; \
|
||||
const bool flag_zf = ccr.z; \
|
||||
const bool flag_vf = ccr.v; \
|
||||
return (flag_nf == flag_vf) && !flag_zf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondLE_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_nf = ccr.n; \
|
||||
const bool flag_zf = ccr.z; \
|
||||
const bool flag_vf = ccr.v; \
|
||||
return (flag_nf != flag_vf) || flag_zf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondGE_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_nf = ccr.n; \
|
||||
const bool flag_vf = ccr.v; \
|
||||
return flag_nf == flag_vf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondL_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_nf = ccr.n; \
|
||||
const bool flag_vf = ccr.v; \
|
||||
return flag_nf != flag_vf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondGU_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_cf = ccr.c; \
|
||||
const bool flag_zf = ccr.z; \
|
||||
return !(flag_cf || flag_zf); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondLEU_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_cf = ccr.c; \
|
||||
const bool flag_zf = ccr.z; \
|
||||
return flag_cf || flag_zf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondCS_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_cf = ccr.c; \
|
||||
return flag_cf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondCC_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_cf = ccr.c; \
|
||||
return !flag_cf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondPOS_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_nf = ccr.n; \
|
||||
return !flag_nf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondNEG_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_nf = ccr.n; \
|
||||
return flag_nf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondVS_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_vf = ccr.v; \
|
||||
return flag_vf; \
|
||||
} \
|
||||
static inline bool \
|
||||
CondVC_ ## cc(const State &state) { \
|
||||
const auto ccr = state.asr.ccr.cc; \
|
||||
const bool flag_vf = ccr.v; \
|
||||
return !flag_vf; \
|
||||
}
|
||||
|
||||
MAKE_CONDITIONS(xcc)
|
||||
MAKE_CONDITIONS(icc)
|
||||
|
||||
#undef MAKE_CONDITIONS
|
||||
|
||||
|
||||
#define MAKE_CONDITIONS(fcc) \
|
||||
static inline bool \
|
||||
CondU_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondG_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x2); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondUG_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x2); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondL_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x1); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondUL_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x1); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondLG_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x1);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondLGU_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x1);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondNE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x1);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x0); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondUE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x0);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondGE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x0);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondUGE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x0);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondLE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x1) \
|
||||
|| (state.fsr.fcc == 0x0); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondULE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x3) \
|
||||
|| (state.fsr.fcc == 0x1) \
|
||||
|| (state.fsr.fcc == 0x0); \
|
||||
} \
|
||||
static inline bool \
|
||||
CondGLE_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x1) \
|
||||
|| (state.fsr.fcc == 0x0);\
|
||||
} \
|
||||
static inline bool \
|
||||
CondO_ ## fcc(const State &state) { \
|
||||
return (state.fsr.fcc == 0x2) \
|
||||
|| (state.fsr.fcc == 0x1) \
|
||||
|| (state.fsr.fcc == 0x0);\
|
||||
}
|
||||
|
||||
MAKE_CONDITIONS(fcc0)
|
||||
MAKE_CONDITIONS(fcc1)
|
||||
MAKE_CONDITIONS(fcc2)
|
||||
MAKE_CONDITIONS(fcc3)
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
CondRZ(const State &state, T cc) {
|
||||
return cc == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
CondRLEZ(const State &state, T cc) {
|
||||
return Signed(cc) <= 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
CondRLZ(const State &state, T cc) {
|
||||
return Signed(cc) < 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
CondRNZ(const State &state, T cc) {
|
||||
return cc != 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
CondRGZ(const State &state, T cc) {
|
||||
return Signed(cc) > 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
CondRGEZ(const State &state, T cc) {
|
||||
return Signed(cc) >= 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CondA_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1000;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
CondN_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0000;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond3_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0111;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond2_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0110;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond23_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0101;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond1_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0100;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond13_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0011;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond12_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0010;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond123_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b0001;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond0_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1001;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond03_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1010;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond02_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1011;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond023_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1100;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond01_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1101;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond013_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1110;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
Cond012_ccc(const State &state) {
|
||||
return state.csr.ccc == 0b1111;
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Trail of Bits, Inc.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename S1>
|
||||
DEF_SEM(LDU, S1 src, R32W dst) {
|
||||
WriteZExt(dst, Read(src));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1>
|
||||
DEF_SEM(LDS, S1 src, R32W dst) {
|
||||
WriteSExt(dst, Read(src));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1>
|
||||
DEF_SEM(LDF, S1 src, R32W dst) {
|
||||
WriteZExt(dst, Read(src));
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(LDD, M32 src1, M32 src2, R32W dst1, R32W dst2) {
|
||||
Write(dst1, Read(src1));
|
||||
Write(dst2, Read(src2));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename D>
|
||||
DEF_SEM(ST, S1 src, D dst) {
|
||||
WriteZExt(dst, Read(src));
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(STD, R32 src1, R32 src2, M32W dst1, M32W dst2) {
|
||||
Write(dst1, Read(src1));
|
||||
Write(dst2, Read(src2));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S, typename D>
|
||||
DEF_SEM(SETHI, S src, D dst) {
|
||||
const auto high_bits = Read(src);
|
||||
Write(dst, high_bits);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D>
|
||||
DEF_SEM(SET, S1 src1, S2 src2, D dst) {
|
||||
const auto high_bits = Read(src1);
|
||||
const auto low_bits = Read(src2);
|
||||
Write(dst, UOr(high_bits, low_bits));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D1, typename D2>
|
||||
DEF_SEM(SETHI_OR, S1 src1, S2 src2, D1 dst1, D2 dst2) {
|
||||
const auto high_bits = Read(src1);
|
||||
const auto low_bits = Read(src2);
|
||||
Write(dst1, high_bits);
|
||||
Write(dst2, UOr(high_bits, low_bits));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S1, typename S2, typename D1, typename D2>
|
||||
DEF_SEM(SETHI_ADD, S1 src1, S2 src2, D1 dst1, D2 dst2) {
|
||||
const auto high_bits = Read(src1);
|
||||
const auto low_bits = Read(src2);
|
||||
Write(dst1, high_bits);
|
||||
Write(dst2, UAdd(high_bits, low_bits));
|
||||
return memory;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DEF_ISEL(LDSB) = LDS<M8>;
|
||||
DEF_ISEL(LDUB) = LDU<M8>;
|
||||
DEF_ISEL(LDSH) = LDS<M16>;
|
||||
DEF_ISEL(LDUH) = LDU<M16>;
|
||||
DEF_ISEL(LD) = LDU<M32>;
|
||||
DEF_ISEL(LDD) = LDD;
|
||||
DEF_ISEL(LDF) = LDF<M32>;
|
||||
DEF_ISEL(LDDF) = LDD;
|
||||
|
||||
DEF_ISEL(STB) = ST<R8, M8W>;
|
||||
DEF_ISEL(STH) = ST<R16, M16W>;
|
||||
DEF_ISEL(ST) = ST<R32, M32W>;
|
||||
DEF_ISEL(STD) = STD;
|
||||
DEF_ISEL(STX) = ST<R32, M32W>;
|
||||
|
||||
DEF_ISEL(STF) = ST<R32, M32W>;
|
||||
DEF_ISEL(STDF) = STD;
|
||||
|
||||
DEF_ISEL(SETHI) = SETHI<I32, R32W>;
|
||||
DEF_ISEL(SET) = SET<I32, I32, R32W>;
|
||||
DEF_ISEL(SETHI_OR) = SETHI_OR<I32, I32, R32W, R32W>;
|
||||
DEF_ISEL(SETHI_ADD) = SETHI_ADD<I32, I32, R32W, R32W>;
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(CASA, R32 src1, R32 src2, R32W dst) {
|
||||
uint32_t rs2 = Read(src2);
|
||||
addr_t addr = Read(src1);
|
||||
auto addr_rs1 = ReadPtr<uint32_t>(addr);
|
||||
uint32_t value_rs1 = Read(addr_rs1);
|
||||
if (value_rs1 == rs2) {
|
||||
Write(WritePtr<uint32_t>(addr), Read(dst));
|
||||
}
|
||||
Write(dst, value_rs1);
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(CASAX, R32 src1, R32 src2, R32W dst) {
|
||||
uint32_t rs2 = Read(src2);
|
||||
addr_t addr = Read(src1);
|
||||
auto addr_rs1 = ReadPtr<uint32_t>(addr);
|
||||
uint32_t value_rs1 = Read(addr_rs1);
|
||||
if (value_rs1 == rs2) {
|
||||
Write(WritePtr<uint32_t>(addr), Read(dst));
|
||||
}
|
||||
WriteZExt(dst, value_rs1);
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(SWAP, M32W addr, R32W rd) {
|
||||
auto old_addr = Read(addr);
|
||||
auto old_rd = Read(rd);
|
||||
WriteZExt(addr, old_rd);
|
||||
WriteZExt(rd, old_addr);
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
DEF_SEM(LDSTUB, M8W src_mem, R dst) {
|
||||
auto mem_val = Read(src_mem);
|
||||
WriteZExt(dst, mem_val);
|
||||
Write(src_mem, static_cast<uint8_t>(0xffu));
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEF_ISEL(CASA) = CASA;
|
||||
DEF_ISEL(CASAX) = CASAX;
|
||||
DEF_ISEL(SWAP) = SWAP;
|
||||
DEF_ISEL(LDSTUB) = LDSTUB<R32W>;
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename S, typename D>
|
||||
DEF_SEM(MOVA_icc, S src, D dst) {
|
||||
WriteZExt(dst, Read(src));
|
||||
return memory;
|
||||
}
|
||||
template <typename S, typename D>
|
||||
DEF_SEM(MOVA_xcc, S src, D dst) {
|
||||
WriteZExt(dst, Read(src));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S, typename D>
|
||||
DEF_SEM(MOVN_icc, S src, D dst) {
|
||||
return memory;
|
||||
}
|
||||
template <typename S, typename D>
|
||||
DEF_SEM(MOVN_xcc, S src, D dst) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEF_ISEL(MOVA_icc) = MOVA_icc<R32, R32W>;
|
||||
DEF_ISEL(MOVA_xcc) = MOVA_xcc<R32, R32W>;
|
||||
DEF_ISEL(MOVN_icc) = MOVN_icc<R32, R32W>;
|
||||
DEF_ISEL(MOVN_xcc) = MOVN_xcc<R32, R32W>;
|
||||
|
||||
|
||||
#define MAKE_SEMANTICS(name, cond, cc) \
|
||||
namespace { \
|
||||
template <typename S, typename D> \
|
||||
DEF_SEM(name ## cond ## _ ## cc, S src, D dst) { \
|
||||
auto new_value = Read(src); \
|
||||
auto old_value = Read(dst); \
|
||||
auto branch_taken = Cond ## cond ## _ ## cc(state); \
|
||||
auto value = Select(branch_taken, new_value, \
|
||||
decltype(new_value)(old_value)); \
|
||||
WriteZExt(dst, value); \
|
||||
return memory; \
|
||||
} \
|
||||
} \
|
||||
DEF_ISEL(MOV ## cond ## _ ## cc) = name ## cond ## _ ## cc<R32, R32W>;
|
||||
|
||||
#define MAKE_SEMANTICS_CC(name, cond) \
|
||||
MAKE_SEMANTICS(name, cond, icc) \
|
||||
MAKE_SEMANTICS(name, cond, xcc)
|
||||
|
||||
#define MAKE_SEMANTICS_FCC(name, cond) \
|
||||
MAKE_SEMANTICS(name, cond, fcc0) \
|
||||
MAKE_SEMANTICS(name, cond, fcc1) \
|
||||
MAKE_SEMANTICS(name, cond, fcc2) \
|
||||
MAKE_SEMANTICS(name, cond, fcc3)
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
MAKE_SEMANTICS_CC(MOV, NE)
|
||||
MAKE_SEMANTICS_CC(MOV, E)
|
||||
MAKE_SEMANTICS_CC(MOV, G)
|
||||
MAKE_SEMANTICS_CC(MOV, LE)
|
||||
MAKE_SEMANTICS_CC(MOV, GE)
|
||||
MAKE_SEMANTICS_CC(MOV, L)
|
||||
MAKE_SEMANTICS_CC(MOV, GU)
|
||||
MAKE_SEMANTICS_CC(MOV, LEU)
|
||||
MAKE_SEMANTICS_CC(MOV, CC)
|
||||
MAKE_SEMANTICS_CC(MOV, CS)
|
||||
MAKE_SEMANTICS_CC(MOV, POS)
|
||||
MAKE_SEMANTICS_CC(MOV, NEG)
|
||||
MAKE_SEMANTICS_CC(MOV, VC)
|
||||
MAKE_SEMANTICS_CC(MOV, VS)
|
||||
|
||||
MAKE_SEMANTICS_FCC(MOVF, U)
|
||||
MAKE_SEMANTICS_FCC(MOVF, G)
|
||||
MAKE_SEMANTICS_FCC(MOVF, UG)
|
||||
MAKE_SEMANTICS_FCC(MOVF, L)
|
||||
MAKE_SEMANTICS_FCC(MOVF, UL)
|
||||
MAKE_SEMANTICS_FCC(MOVF, LG)
|
||||
MAKE_SEMANTICS_FCC(MOVF, NE)
|
||||
MAKE_SEMANTICS_FCC(MOVF, E)
|
||||
MAKE_SEMANTICS_FCC(MOVF, UE)
|
||||
MAKE_SEMANTICS_FCC(MOVF, GE)
|
||||
MAKE_SEMANTICS_FCC(MOVF, UGE)
|
||||
MAKE_SEMANTICS_FCC(MOVF, LE)
|
||||
MAKE_SEMANTICS_FCC(MOVF, ULE)
|
||||
MAKE_SEMANTICS_FCC(MOVF, O)
|
||||
|
||||
}
|
||||
|
||||
#undef MAKE_SEMANTICS
|
||||
#undef MAKE_SEMANTICS_CC
|
||||
#undef MAKE_SEMANTICS_FCC
|
||||
|
||||
#define MAKE_SEMANTICS(name, cond) \
|
||||
namespace { \
|
||||
template <typename C, typename S, typename D> \
|
||||
DEF_SEM(name ## cond, C reg_cc, S src, D dst) { \
|
||||
auto new_value = Read(src); \
|
||||
auto old_value = Read(dst); \
|
||||
auto cc = Read(reg_cc); \
|
||||
auto cond_taken = CondR ## cond(state, cc); \
|
||||
auto value = Select(cond_taken, new_value, decltype(new_value)(old_value)); \
|
||||
WriteZExt(dst, value); \
|
||||
return memory; \
|
||||
} \
|
||||
} \
|
||||
DEF_ISEL(MOVR ## cond) = name ## cond<R32, R32, R32W>;
|
||||
|
||||
MAKE_SEMANTICS(MOVR, Z)
|
||||
MAKE_SEMANTICS(MOVR, LEZ)
|
||||
MAKE_SEMANTICS(MOVR, LZ)
|
||||
MAKE_SEMANTICS(MOVR, NZ)
|
||||
MAKE_SEMANTICS(MOVR, GZ)
|
||||
MAKE_SEMANTICS(MOVR, GEZ)
|
||||
|
||||
#undef MAKE_SEMANTICS
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(FMoveAlwaysSingle, V32 src, V32W dst) {
|
||||
auto new_val = FExtractV32(FReadV32(src), 0);
|
||||
FWriteV32(dst, new_val);
|
||||
WriteTrunc(FSR_CEXC, 0);
|
||||
WriteTrunc(FSR_FTT, 0);
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(FMoveNeverSingle, V32 src, V32W dst) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(FMoveAlwaysDouble, V64 src, V64W dst) {
|
||||
auto new_val = FExtractV64(FReadV64(src), 0);
|
||||
FWriteV64(dst, new_val);
|
||||
WriteTrunc(FSR_CEXC, 0);
|
||||
WriteTrunc(FSR_FTT, 0);
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(FMoveNeverDouble, V64 src, V64W dst) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(FMoveAlwaysQuad, V64 src, V64W dst) {
|
||||
auto new_val = FExtractV64(FReadV64(src), 0);
|
||||
FWriteV64(dst, new_val);
|
||||
WriteTrunc(FSR_CEXC, 0);
|
||||
WriteTrunc(FSR_FTT, 0);
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(FMoveNeverQuad, V64 src, V64W dst) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEF_ISEL(FMOVSA_icc) = FMoveAlwaysSingle;
|
||||
DEF_ISEL(FMOVSA_xcc) = FMoveAlwaysSingle;
|
||||
DEF_ISEL(FMOVSA_fcc0) = FMoveAlwaysSingle;
|
||||
DEF_ISEL(FMOVSA_fcc1) = FMoveAlwaysSingle;
|
||||
DEF_ISEL(FMOVSA_fcc2) = FMoveAlwaysSingle;
|
||||
DEF_ISEL(FMOVSA_fcc3) = FMoveAlwaysSingle;
|
||||
|
||||
DEF_ISEL(FMOVSN_icc) = FMoveNeverSingle;
|
||||
DEF_ISEL(FMOVSN_xcc) = FMoveNeverSingle;
|
||||
DEF_ISEL(FMOVSN_fcc0) = FMoveNeverSingle;
|
||||
DEF_ISEL(FMOVSN_fcc1) = FMoveNeverSingle;
|
||||
DEF_ISEL(FMOVSN_fcc2) = FMoveNeverSingle;
|
||||
DEF_ISEL(FMOVSN_fcc3) = FMoveNeverSingle;
|
||||
|
||||
DEF_ISEL(FMOVDA_icc) = FMoveAlwaysDouble;
|
||||
DEF_ISEL(FMOVDA_xcc) = FMoveAlwaysDouble;
|
||||
DEF_ISEL(FMOVDA_fcc0) = FMoveAlwaysDouble;
|
||||
DEF_ISEL(FMOVDA_fcc1) = FMoveAlwaysDouble;
|
||||
DEF_ISEL(FMOVDA_fcc2) = FMoveAlwaysDouble;
|
||||
DEF_ISEL(FMOVDA_fcc3) = FMoveAlwaysDouble;
|
||||
|
||||
DEF_ISEL(FMOVDN_icc) = FMoveNeverDouble;
|
||||
DEF_ISEL(FMOVDN_xcc) = FMoveNeverDouble;
|
||||
DEF_ISEL(FMOVDN_fcc0) = FMoveNeverDouble;
|
||||
DEF_ISEL(FMOVDN_fcc1) = FMoveNeverDouble;
|
||||
DEF_ISEL(FMOVDN_fcc2) = FMoveNeverDouble;
|
||||
DEF_ISEL(FMOVDN_fcc3) = FMoveNeverDouble;
|
||||
|
||||
DEF_ISEL(FMOVQA_icc) = FMoveAlwaysQuad;
|
||||
DEF_ISEL(FMOVQA_xcc) = FMoveAlwaysQuad;
|
||||
DEF_ISEL(FMOVQA_fcc0) = FMoveAlwaysQuad;
|
||||
DEF_ISEL(FMOVQA_fcc1) = FMoveAlwaysQuad;
|
||||
DEF_ISEL(FMOVQA_fcc2) = FMoveAlwaysQuad;
|
||||
DEF_ISEL(FMOVQA_fcc3) = FMoveAlwaysQuad;
|
||||
|
||||
DEF_ISEL(FMOVQN_icc) = FMoveNeverQuad;
|
||||
DEF_ISEL(FMOVQN_xcc) = FMoveNeverQuad;
|
||||
DEF_ISEL(FMOVQN_fcc0) = FMoveNeverQuad;
|
||||
DEF_ISEL(FMOVQN_fcc1) = FMoveNeverQuad;
|
||||
DEF_ISEL(FMOVQN_fcc2) = FMoveNeverQuad;
|
||||
DEF_ISEL(FMOVQN_fcc3) = FMoveNeverQuad;
|
||||
|
||||
|
||||
#define MAKE_SEMANTICS(name, cond, cc) \
|
||||
namespace { \
|
||||
DEF_SEM(FMOVS ## cond ## _ ## cc, V32 src, V32W dst) { \
|
||||
auto new_val = FExtractV32(FReadV32(src), 0); \
|
||||
auto old_val = FExtractV32(FReadV32(dst), 0); \
|
||||
auto branch_taken = Cond ## cond ## _ ## cc(state); \
|
||||
auto value = Select(branch_taken, new_val, \
|
||||
decltype(new_val)(old_val)); \
|
||||
FWriteV32(dst, value); \
|
||||
WriteTrunc(FSR_CEXC, 0); \
|
||||
WriteTrunc(FSR_FTT, 0); \
|
||||
return memory; \
|
||||
} \
|
||||
DEF_SEM(FMOVD ## cond ## _ ## cc, V64 src, V64W dst) { \
|
||||
auto new_val = FExtractV64(FReadV64(src), 0); \
|
||||
auto old_val = FExtractV64(FReadV64(dst), 0); \
|
||||
auto branch_taken = Cond ## cond ## _ ## cc(state); \
|
||||
auto value = Select(branch_taken, new_val, \
|
||||
decltype(new_val)(old_val)); \
|
||||
FWriteV64(dst, value); \
|
||||
WriteTrunc(FSR_CEXC, 0); \
|
||||
WriteTrunc(FSR_FTT, 0); \
|
||||
return memory; \
|
||||
} \
|
||||
DEF_SEM(FMOVQ ## cond ## _ ## cc, V64 src, V64W dst) { \
|
||||
auto new_val = FExtractV64(FReadV64(src), 0); \
|
||||
auto old_val = FExtractV64(FReadV64(dst), 0); \
|
||||
auto branch_taken = Cond ## cond ## _ ## cc(state); \
|
||||
auto value = Select(branch_taken, new_val, \
|
||||
decltype(new_val)(old_val)); \
|
||||
FWriteV64(dst, value); \
|
||||
WriteTrunc(FSR_CEXC, 0); \
|
||||
WriteTrunc(FSR_FTT, 0); \
|
||||
return memory; \
|
||||
} \
|
||||
} \
|
||||
DEF_ISEL(FMOVS ## cond ## _ ## cc) = FMOVS ## cond ## _ ## cc; \
|
||||
DEF_ISEL(FMOVD ## cond ## _ ## cc) = FMOVD ## cond ## _ ## cc; \
|
||||
DEF_ISEL(FMOVQ ## cond ## _ ## cc) = FMOVQ ## cond ## _ ## cc;
|
||||
|
||||
#define MAKE_SEMANTICS_CC(name, cond) \
|
||||
MAKE_SEMANTICS(name, cond, icc) \
|
||||
MAKE_SEMANTICS(name, cond, xcc)
|
||||
|
||||
#define MAKE_SEMANTICS_FCC(name, cond) \
|
||||
MAKE_SEMANTICS(name, cond, fcc0) \
|
||||
MAKE_SEMANTICS(name, cond, fcc1) \
|
||||
MAKE_SEMANTICS(name, cond, fcc2) \
|
||||
MAKE_SEMANTICS(name, cond, fcc3)
|
||||
|
||||
MAKE_SEMANTICS_CC(FMOV, NE)
|
||||
MAKE_SEMANTICS_CC(FMOV, E)
|
||||
MAKE_SEMANTICS_CC(FMOV, G)
|
||||
MAKE_SEMANTICS_CC(FMOV, LE)
|
||||
MAKE_SEMANTICS_CC(FMOV, GE)
|
||||
MAKE_SEMANTICS_CC(FMOV, L)
|
||||
MAKE_SEMANTICS_CC(FMOV, GU)
|
||||
MAKE_SEMANTICS_CC(FMOV, LEU)
|
||||
MAKE_SEMANTICS_CC(FMOV, CC)
|
||||
MAKE_SEMANTICS_CC(FMOV, CS)
|
||||
MAKE_SEMANTICS_CC(FMOV, POS)
|
||||
MAKE_SEMANTICS_CC(FMOV, NEG)
|
||||
MAKE_SEMANTICS_CC(FMOV, VC)
|
||||
MAKE_SEMANTICS_CC(FMOV, VS)
|
||||
|
||||
MAKE_SEMANTICS_FCC(FMOV, U)
|
||||
MAKE_SEMANTICS_FCC(FMOV, G)
|
||||
MAKE_SEMANTICS_FCC(FMOV, UG)
|
||||
MAKE_SEMANTICS_FCC(FMOV, L)
|
||||
MAKE_SEMANTICS_FCC(FMOV, UL)
|
||||
MAKE_SEMANTICS_FCC(FMOV, LG)
|
||||
MAKE_SEMANTICS_FCC(FMOV, NE)
|
||||
MAKE_SEMANTICS_FCC(FMOV, E)
|
||||
MAKE_SEMANTICS_FCC(FMOV, UE)
|
||||
MAKE_SEMANTICS_FCC(FMOV, GE)
|
||||
MAKE_SEMANTICS_FCC(FMOV, UGE)
|
||||
MAKE_SEMANTICS_FCC(FMOV, LE)
|
||||
MAKE_SEMANTICS_FCC(FMOV, ULE)
|
||||
MAKE_SEMANTICS_FCC(FMOV, O)
|
||||
|
||||
#undef MAKE_SEMANTICS
|
||||
#undef MAKE_SEMANTICS_CC
|
||||
#undef MAKE_SEMANTICS_FCC
|
||||
|
||||
#define MAKE_SEMANTICS(name, cond) \
|
||||
namespace { \
|
||||
DEF_SEM(name ## S ## cond, R32 reg_cc, V32 src, V32W dst) { \
|
||||
auto new_val = FExtractV32(FReadV32(src), 0); \
|
||||
auto old_val = FExtractV32(FReadV32(dst), 0); \
|
||||
auto cc = Read(reg_cc); \
|
||||
auto cond_taken = CondR ## cond(state, cc); \
|
||||
auto value = Select(cond_taken, \
|
||||
new_val, \
|
||||
decltype(new_val)(old_val)); \
|
||||
FWriteV32(dst, value); \
|
||||
WriteTrunc(FSR_CEXC, 0); \
|
||||
WriteTrunc(FSR_FTT, 0); \
|
||||
return memory; \
|
||||
} \
|
||||
DEF_SEM(name ## D ## cond, R32 reg_cc, V64 src, V64W dst) { \
|
||||
auto new_val = FExtractV64(FReadV64(src), 0); \
|
||||
auto old_val = FExtractV64(FReadV64(dst), 0); \
|
||||
auto cc = Read(reg_cc); \
|
||||
auto cond_taken = CondR ## cond(state, cc); \
|
||||
auto value = Select(cond_taken, \
|
||||
new_val, \
|
||||
decltype(new_val)(old_val)); \
|
||||
FWriteV64(dst, value); \
|
||||
WriteTrunc(FSR_CEXC, 0); \
|
||||
WriteTrunc(FSR_FTT, 0); \
|
||||
return memory; \
|
||||
} \
|
||||
DEF_SEM(name ## Q ## cond, R32 reg_cc, V64 src, V64W dst) { \
|
||||
auto new_val = FExtractV64(FReadV64(src), 0); \
|
||||
auto old_val = FExtractV64(FReadV64(dst), 0); \
|
||||
auto cc = Read(reg_cc); \
|
||||
auto cond_taken = CondR ## cond(state, cc); \
|
||||
auto value = Select(cond_taken, \
|
||||
new_val, \
|
||||
decltype(new_val)(old_val)); \
|
||||
FWriteV64(dst, value); \
|
||||
WriteTrunc(FSR_CEXC, 0); \
|
||||
WriteTrunc(FSR_FTT, 0); \
|
||||
return memory; \
|
||||
} \
|
||||
} \
|
||||
DEF_ISEL(name ## S ## cond) = name ## S ## cond; \
|
||||
DEF_ISEL(name ## D ## cond) = name ## D ## cond; \
|
||||
DEF_ISEL(name ## Q ## cond) = name ## Q ## cond;
|
||||
|
||||
MAKE_SEMANTICS(FMOVR, Z)
|
||||
MAKE_SEMANTICS(FMOVR, LEZ)
|
||||
MAKE_SEMANTICS(FMOVR, LZ)
|
||||
MAKE_SEMANTICS(FMOVR, NZ)
|
||||
MAKE_SEMANTICS(FMOVR, GZ)
|
||||
MAKE_SEMANTICS(FMOVR, GEZ)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user