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:
Peter Goodman
2020-10-28 15:11:42 -04:00
committed by GitHub
parent 4aea5a8f2a
commit 3808e9951d
187 changed files with 16701 additions and 2446 deletions
+1 -1
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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")
+1 -3
View File
@@ -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}"
)
+15 -12
View File
@@ -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);
+64 -6
View File
@@ -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)
+7 -5
View File
@@ -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)
+68
View File
@@ -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
+96
View File
@@ -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
+350
View File
@@ -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;
+361
View File
@@ -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;
+44
View File
@@ -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 &reg_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 &reg_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 &reg_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
+20
View File
@@ -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"
+110
View File
@@ -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
+28 -26
View File
@@ -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 *>;
+2 -2
View File
@@ -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";
}
+46
View File
@@ -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 {
@@ -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"
+78
View File
@@ -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()
@@ -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>
+76 -37
View File
@@ -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 &reg = 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");
+44
View File
@@ -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;
+26 -13
View File
@@ -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"
+504
View File
@@ -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
+44
View File
@@ -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}"
)
+332
View File
@@ -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
+29
View File
@@ -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
+70
View File
@@ -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)
+244
View File
@@ -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"
+316
View File
@@ -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;
+239
View File
@@ -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
+316
View File
@@ -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;
}
+486
View File
@@ -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