diff --git a/CMakeLists.txt b/CMakeLists.txt index cad52ecfc..b4e002614 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,9 @@ find_package(glog CONFIG REQUIRED) # Google gflags find_package(gflags CONFIG REQUIRED) +# Python interpreter +find_package(Python COMPONENTS Interpreter) + set(sleigh_ENABLE_TESTS OFF) set(sleigh_ADDITIONAL_PATCHES "${CMAKE_CURRENT_SOURCE_DIR}/patches/sleigh/x86-ia.patch;${CMAKE_CURRENT_SOURCE_DIR}/patches/sleigh/arm-thumb.patch" CACHE STRING "" FORCE) diff --git a/bin/differential_tester_x86/CMakeLists.txt b/bin/differential_tester_x86/CMakeLists.txt index 23c36ecea..a80a274ab 100644 --- a/bin/differential_tester_x86/CMakeLists.txt +++ b/bin/differential_tester_x86/CMakeLists.txt @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -find_package(Python COMPONENTS Interpreter) add_executable( lift-and-compare LiftAndCompare.cpp diff --git a/cmake/options.cmake b/cmake/options.cmake index 39a6d51d2..9849978dc 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -17,6 +17,11 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUA message(STATUS "aarch64 tests enabled") set(can_enable_testing_aarch64 TRUE) endif() + + if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64" AND "${PLATFORM_NAME}" STREQUAL "macos") + message(STATUS "aarch64 tests enabled") + set(can_enable_testing_aarch64 TRUE) + endif() endif() set(REMILL_SOURCE_DIR "${PROJECT_SOURCE_DIR}" CACHE PATH "Root directory of remill source code") @@ -29,4 +34,4 @@ cmake_dependent_option(REMILL_ENABLE_TESTING "Build your tests" ON "can_enable_t cmake_dependent_option(REMILL_ENABLE_TESTING_X86 "Build your tests" ON "REMILL_ENABLE_TESTING;can_enable_testing_x86" OFF) cmake_dependent_option(REMILL_ENABLE_TESTING_AARCH64 "Build your tests" ON "REMILL_ENABLE_TESTING;can_enable_testing_aarch64" OFF) cmake_dependent_option(REMILL_ENABLE_TESTING_SLEIGH_THUMB "Build cross platform sliegh tests" ON "REMILL_ENABLE_TESTING" OFF) -cmake_dependent_option(REMILL_ENABLE_DIFFERENTIAL_TESTING "Build cross platform differential testing of sleigh x86" ON "REMILL_ENABLE_TESTING" OFF) \ No newline at end of file +cmake_dependent_option(REMILL_ENABLE_DIFFERENTIAL_TESTING "Build cross platform differential testing of sleigh x86" ON "REMILL_ENABLE_TESTING" OFF) diff --git a/include/remill/Arch/AArch64/Runtime/Types.h b/include/remill/Arch/AArch64/Runtime/Types.h index 011a91db9..22cd221c9 100644 --- a/include/remill/Arch/AArch64/Runtime/Types.h +++ b/include/remill/Arch/AArch64/Runtime/Types.h @@ -49,6 +49,7 @@ typedef MVnW MV16W; typedef MVnW MV32W; typedef MVnW MV64W; typedef MVnW MV128W; +typedef MVnW MV256W; typedef Mn M8; typedef Mn M16; diff --git a/lib/Arch/AArch64/Semantics/DATAXFER.cpp b/lib/Arch/AArch64/Semantics/DATAXFER.cpp index 6175da875..3efbc69bc 100644 --- a/lib/Arch/AArch64/Semantics/DATAXFER.cpp +++ b/lib/Arch/AArch64/Semantics/DATAXFER.cpp @@ -72,15 +72,15 @@ DEF_SEM(STP_D, V64 src1, V64 src2, MV128W dst) { // remill/remill/Arch/Runtime/Operators.h:437:1: error: static_assert failed "Invalid value size for MVnW." // MAKE_MWRITEV(U, 128, dqwords, 128, uint128_t) -// DEF_SEM(STP_Q, V128 src1, V128 src2, MV128W dst) { -// auto src1_vec = UReadV128(src1); -// auto src2_vec = UReadV128(src2); -// uint128v2_t tmp_vec = {}; -// tmp_vec = UInsertV128(tmp_vec, 0, UExtractV128(src1_vec, 0)); -// tmp_vec = UInsertV128(tmp_vec, 1, UExtractV128(src2_vec, 0)); -// UWriteV128(dst, tmp_vec); -// return memory; -// } +DEF_SEM(STP_Q, V128 src1, V128 src2, MV256W dst) { + auto src1_vec = UReadV128(src1); + auto src2_vec = UReadV128(src2); + uint128v2_t tmp_vec = {}; + tmp_vec = UInsertV128(tmp_vec, 0, UExtractV128(src1_vec, 0)); + tmp_vec = UInsertV128(tmp_vec, 1, UExtractV128(src2_vec, 0)); + UWriteV128(dst, tmp_vec); + return memory; +} } // namespace DEF_ISEL(STP_32_LDSTPAIR_PRE) = StorePairUpdateIndex32; @@ -95,7 +95,7 @@ DEF_ISEL(STP_64_LDSTPAIR_OFF) = StorePair64; DEF_ISEL(STP_S_LDSTPAIR_OFF) = STP_S; DEF_ISEL(STP_D_LDSTPAIR_OFF) = STP_D; -// DEF_ISEL(STP_Q_LDSTPAIR_OFF) = STP_Q; +DEF_ISEL(STP_Q_LDSTPAIR_OFF) = STP_Q; namespace { diff --git a/lib/Arch/Runtime/HyperCall.cpp b/lib/Arch/Runtime/HyperCall.cpp index 62f5ee253..5b9579c2b 100644 --- a/lib/Arch/Runtime/HyperCall.cpp +++ b/lib/Arch/Runtime/HyperCall.cpp @@ -279,7 +279,9 @@ Memory *__remill_sync_hyper_call(State &state, Memory *mem, mem = __remill_aarch64_emulate_instruction(mem); break; - case SyncHyperCall::kAArch64Breakpoint: asm volatile("bkpt" :); break; + case SyncHyperCall::kAArch64Breakpoint: + asm volatile("brk #0x0"); + break; #elif REMILL_HYPERCALL_SPARC32 || REMILL_HYPERCALL_SPARC64 diff --git a/scripts/post_process_asm.py b/scripts/post_process_asm.py new file mode 100644 index 000000000..c1b0ee186 --- /dev/null +++ b/scripts/post_process_asm.py @@ -0,0 +1,32 @@ +# Copyright (c) 2022 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. + +""" +Post-process an assembly file and replace all @N@ symbols with newlines. + +In Remill, we use pre-processor macros to generate assembly code. However, +macros cannot expand across multiple lines so there isn't a way to delimit +statements. To get around this limitation, we use the @N@ symbol to represent +a new line in the macro expansion and then use this post-processing script to +translate them into actual newlines. + +Usage: post_process_asm.py INPUT_FILE OUTPUT_FILE +""" + +import sys + +with open(sys.argv[1]) as pre_processed, open(sys.argv[2], "w") as post_processed: + for line in pre_processed: + line = line.replace("@N@", "\n") + post_processed.write(line) diff --git a/tests/AArch64/CMakeLists.txt b/tests/AArch64/CMakeLists.txt index 1dee6d921..98d96e316 100644 --- a/tests/AArch64/CMakeLists.txt +++ b/tests/AArch64/CMakeLists.txt @@ -19,14 +19,13 @@ enable_testing() enable_language(ASM) add_executable(lift-aarch64-tests - EXCLUDE_FROM_ALL Lift.cpp - Tests.S + lift-post-processed-tests.S ) set_target_properties(lift-aarch64-tests PROPERTIES POSITION_INDEPENDENT_CODE ON - COMPILE_FLAGS "-fPIC -pie" + COMPILE_FLAGS "-fPIC" ) target_compile_options(lift-aarch64-tests @@ -46,15 +45,14 @@ target_include_directories(lift-aarch64-tests PUBLIC ${PROJECT_INCLUDEDIRECTORIE target_include_directories(lift-aarch64-tests PRIVATE ${CMAKE_SOURCE_DIR}) add_executable(run-aarch64-tests - EXCLUDE_FROM_ALL Run.cpp - Tests.S + run-post-processed-tests.S tests_aarch64.S ) set_target_properties(run-aarch64-tests PROPERTIES POSITION_INDEPENDENT_CODE ON - COMPILE_FLAGS "-fPIC -pie" + COMPILE_FLAGS "-fPIC" OBJECT_DEPENDS "${AARCH64_TEST_FILES}" ) @@ -68,11 +66,35 @@ add_custom_command( OUTPUT tests_aarch64.S COMMAND ${CMAKE_BC_COMPILER} -Wno-override-module - -S -O1 -g0 + -S -O0 -g0 -c tests_aarch64.bc -o tests_aarch64.S -mllvm -opaque-pointers DEPENDS tests_aarch64.bc + ) + +add_custom_command( + OUTPUT run-pre-processed-tests.S + COMMAND ${CMAKE_CXX_COMPILER} "-I${REMILL_SOURCE_DIR}" -o run-pre-processed-tests.S -E "${CMAKE_CURRENT_SOURCE_DIR}/Tests.S" + DEPENDS Tests.S +) + +add_custom_command( + OUTPUT lift-pre-processed-tests.S + COMMAND ${CMAKE_CXX_COMPILER} "-I${REMILL_SOURCE_DIR}" -D IN_TEST_GENERATOR -o lift-pre-processed-tests.S -E "${CMAKE_CURRENT_SOURCE_DIR}/Tests.S" + DEPENDS Tests.S +) + +add_custom_command( + OUTPUT run-post-processed-tests.S + COMMAND ${Python_EXECUTABLE} "${REMILL_SOURCE_DIR}/scripts/post_process_asm.py" run-pre-processed-tests.S run-post-processed-tests.S + DEPENDS run-pre-processed-tests.S +) + +add_custom_command( + OUTPUT lift-post-processed-tests.S + COMMAND ${Python_EXECUTABLE} "${REMILL_SOURCE_DIR}/scripts/post_process_asm.py" lift-pre-processed-tests.S lift-post-processed-tests.S + DEPENDS lift-pre-processed-tests.S ) target_link_libraries(run-aarch64-tests PUBLIC remill ${PROJECT_LIBRARIES}) diff --git a/tests/AArch64/DATAXFER/STP_n_LDSTPAIR_OFF.S b/tests/AArch64/DATAXFER/STP_n_LDSTPAIR_OFF.S index a78560e5c..761342bba 100644 --- a/tests/AArch64/DATAXFER/STP_n_LDSTPAIR_OFF.S +++ b/tests/AArch64/DATAXFER/STP_n_LDSTPAIR_OFF.S @@ -64,16 +64,12 @@ TEST_INPUTS(0) stp d4, d5, [x3, #64] TEST_END -// MvW type isnt supported -// remill/remill/Arch/Runtime/Operators.h:437:1: error: static_assert failed "Invalid value size for MVnW." -// MAKE_MWRITEV(U, 128, dqwords, 128, uint128_t) - /* STP , , [{, #}] */ -// TEST_BEGIN(STP_Q_LDSTPAIR_OFF, stp_q0_q1_m256_off, 1) -// TEST_INPUTS(0) +TEST_BEGIN(STP_Q_LDSTPAIR_OFF, stp_q0_q1_m256_off, 1) +TEST_INPUTS(0) -// add x3, sp, #-256 -// stp q0, q1, [x3, #0] -// stp q2, q3, [x3, #32] -// stp q4, q5, [x3, #64] -// TEST_END + add x3, sp, #-256 + stp q0, q1, [x3, #0] + stp q2, q3, [x3, #32] + stp q4, q5, [x3, #64] +TEST_END diff --git a/tests/AArch64/Lift.cpp b/tests/AArch64/Lift.cpp index 1acb4b60c..1ca387bc6 100644 --- a/tests/AArch64/Lift.cpp +++ b/tests/AArch64/Lift.cpp @@ -37,6 +37,7 @@ #include "remill/BC/IntrinsicTable.h" #include "remill/BC/Lifter.h" #include "remill/BC/Util.h" +#include "remill/BC/Version.h" #include "remill/OS/OS.h" #include "tests/AArch64/Test.h" diff --git a/tests/AArch64/Tests.S b/tests/AArch64/Tests.S index ed902f6f7..9fcb1533f 100644 --- a/tests/AArch64/Tests.S +++ b/tests/AArch64/Tests.S @@ -27,8 +27,14 @@ /* Note: Apple mangles C symbol names to have a leading underscore. */ #ifdef __APPLE__ # define SYMBOL(x) CAT(_, x) +# define SYMBOL_PAGE(x) SYMBOL(x)@PAGE +# define SYMBOL_PAGEOFF(x) :lo12:SYMBOL(x)@PAGEOFF +# define CONST_SECTION .const #else # define SYMBOL(x) x +# define SYMBOL_PAGE(x) SYMBOL(x) +# define SYMBOL_PAGEOFF(x) :lo12:SYMBOL(x) +# define CONST_SECTION .rodata #endif #define FUNC_NAME(instr_name, num_args) \ @@ -38,8 +44,8 @@ # define TEST_PROLOGUE #else # define TEST_PROLOGUE \ - adrp x28, SYMBOL(gNativeState) ; \ - add x28, x28, :lo12:SYMBOL(gNativeState) ; + adrp x28, SYMBOL_PAGE(gNativeState) @N@ \ + add x28, x28, SYMBOL_PAGEOFF(gNativeState) @N@ #endif /* IN_TEST_GENERATOR */ /* Defines the beginning of a test function. The key detail is that tests @@ -52,32 +58,31 @@ * `__aarch64_test_table_end` symbols, respectively. */ #define TEST_BEGIN(isel_name, instr_name, num_args) \ - .text ; \ + .text @N@ \ \ - .align 16 ; \ - .globl SYMBOL(FUNC_NAME(instr_name, num_args)) ; \ + .align 16 @N@ \ + .globl SYMBOL(FUNC_NAME(instr_name, num_args)) @N@ \ \ -SYMBOL(FUNC_NAME(instr_name, num_args)): ; \ - .section "__aarch64_test_table", "a" ; \ - .balign 128 ; \ +SYMBOL(FUNC_NAME(instr_name, num_args)): @N@ \ + .section "__aarch64_test_table", "a" @N@ \ + .balign 128 @N@ \ 1: \ - .quad 3f ; \ - .quad 7f ; \ - .quad 2f ; \ - .quad 4f ; \ - .quad 5f ; \ - .quad num_args ; \ - .quad 6f ; \ + .quad 3f @N@ \ + .quad 7f @N@ \ + .quad 2f @N@ \ + .quad 4f @N@ \ + .quad 5f @N@ \ + .quad num_args @N@ \ + .quad 6f @N@ \ \ - .rodata ; \ + CONST_SECTION @N@ \ 2: \ - .asciz TO_STRING(FUNC_NAME(instr_name, num_args)) ; \ + .asciz TO_STRING(FUNC_NAME(instr_name, num_args)) @N@ \ 6: \ - .asciz TO_STRING(isel_name) ; \ + .asciz TO_STRING(isel_name) @N@ \ \ - .text ; \ + .text @N@ \ 3: \ - .cfi_startproc ; \ TEST_PROLOGUE /* Note: The test end address is placed *before* the `RET` so that we can @@ -87,33 +92,31 @@ SYMBOL(FUNC_NAME(instr_name, num_args)): ; \ #ifdef IN_TEST_GENERATOR # define TEST_END \ 7: \ - .cfi_endproc ; \ - .section "__aarch64_test_table", "a" ; \ - .quad 0 ; \ - hlt #0 ; + .section "__aarch64_test_table", "a" @N@ \ + .quad 0 @N@ \ + hlt #0 @N@ #else # define TEST_END \ 7: \ - b SYMBOL(__aarch64_save_state_after) ; \ - .cfi_endproc ; \ - .section "__aarch64_test_table", "a" ; \ - .quad 0 ; \ - .text ; \ - hlt #0 ; + b SYMBOL(__aarch64_save_state_after) @N@ \ + .section "__aarch64_test_table", "a" @N@ \ + .quad 0 @N@ \ + .text @N@ \ + hlt #0 @N@ #endif /* IN_TEST_GENERATOR */ /* Defines the possible inputs to provide test. We add an extra 3 null inputs * at the end so that we can purposely 'overflow' when accessing the array so * that we can always specify 3 inputs, even if the program uses fewer. */ #define TEST_INPUTS(...) \ - .data ; \ - .balign 8 ; \ + .data @N@ \ + .balign 8 @N@ \ 4: \ - .quad __VA_ARGS__ ; \ + .quad __VA_ARGS__ @N@ \ 5: \ - .quad 0, 0, 0; \ - .text ; + .quad 0, 0, 0 @N@ \ + .text @N@ #ifndef IN_TEST_GENERATOR .data @@ -145,13 +148,12 @@ SYMBOL(vec_data): .align 16 .globl SYMBOL(InvokeTestCase) SYMBOL(InvokeTestCase): - .cfi_startproc msr fpcr, xzr msr fpsr, xzr /* Fill in q0 through q7 with dummy values. */ - adrp x28, SYMBOL(vec_data) - add x28, x28, :lo12:SYMBOL(vec_data) + adrp x28, SYMBOL_PAGE(vec_data) + add x28, x28, SYMBOL_PAGEOFF(vec_data) ldur q0, [x28, #0] ldur q1, [x28, #16] ldur q2, [x28, #32] @@ -162,8 +164,8 @@ SYMBOL(InvokeTestCase): ldur q7, [x28, #128] /* Get the address of stack save slots into x28 */ - adrp x28, SYMBOL(gStackSaveSlots) - add x28, x28, :lo12:SYMBOL(gStackSaveSlots) + adrp x28, SYMBOL_PAGE(gStackSaveSlots) + add x28, x28, SYMBOL_PAGEOFF(gStackSaveSlots) str x29, [x28, #8] /* Save x29 into slot 1 */ mov x29, sp @@ -171,47 +173,43 @@ SYMBOL(InvokeTestCase): ldr x29, [x28, #8] /* Restore x29 */ /* Swap off of the native stack */ - adrp x28, SYMBOL(gStackSwitcher) - add x28, x28, :lo12:SYMBOL(gStackSwitcher) + adrp x28, SYMBOL_PAGE(gStackSwitcher) + add x28, x28, SYMBOL_PAGEOFF(gStackSwitcher) ldr x28, [x28] mov sp, x28 /* Start by saving the current native state into the `gLiftedState` * structure. This will be used as the initial state when running the * lifted tests. */ - adrp x28, SYMBOL(gLiftedState) - add x28, x28, :lo12:SYMBOL(gLiftedState) + adrp x28, SYMBOL_PAGE(gLiftedState) + add x28, x28, SYMBOL_PAGEOFF(gLiftedState) #include "generated/Arch/AArch64/SaveState.S" /* Branch to the test to run */ - adrp x28, SYMBOL(gTestToRun) - add x28, x28, :lo12:SYMBOL(gTestToRun) + adrp x28, SYMBOL_PAGE(gTestToRun) + add x28, x28, SYMBOL_PAGEOFF(gTestToRun) ldr x28, [x28] msr fpcr, xzr msr fpsr, xzr br x28 - .cfi_endproc - .align 16 .globl SYMBOL(__aarch64_save_state_after) SYMBOL(__aarch64_save_state_after): - .cfi_startproc /* Save the current native state into the `gNativeState`, which now * contains the post-test state for eventual comparison against lifted * execution. Finally, go and restore the originally saved state. */ - adrp x28, SYMBOL(gNativeState) - add x28, x28, :lo12:SYMBOL(gNativeState) + adrp x28, SYMBOL_PAGE(gNativeState) + add x28, x28, SYMBOL_PAGEOFF(gNativeState) #include "generated/Arch/AArch64/SaveState.S" /*#include "generated/Arch/AArch64/RestoreState.S"*/ - adrp x28, SYMBOL(gStackSaveSlots) - add x28, x28, :lo12:SYMBOL(gStackSaveSlots) + adrp x28, SYMBOL_PAGE(gStackSaveSlots) + add x28, x28, SYMBOL_PAGEOFF(gStackSaveSlots) ldr x28, [x28] /* Load the saves SP from slot 0 */ mov sp, x28 ret - .cfi_endproc #endif /* IN_TEST_GENERATOR */ /* Create a symbol that represents the beginning of the test @@ -428,4 +426,3 @@ SYMBOL(__aarch64_test_table_begin): .section "__aarch64_test_table", "a" .globl SYMBOL(__aarch64_test_table_end) SYMBOL(__aarch64_test_table_end): -