使用CMake完成SGX SDK程序的编译

前言

在使用SGX保护大工程中的一部分的时候,大工程往往使用的是CMake完成工程源码的编译并产生可执行文件,但是SGX SDK给的例子都是使用Makefile完成编译,为了在大工程中使用SGX SDK功能,那么就要实现使用CMake编译SGX SDK程序

准备工作

我的环境仍然是使用的以前SGX文章中的环境,在此不做赘述,现阶段我使用的SDK SDK版本是2.0版本,下载地址是https://github.com/01org/linux-sgx,使用的CMake版本如下:

dck@dck-Precision-Tower-3620:~/SGX-develop/test-cmake/SampleEnclave/build$ cmake --version
cmake version 3.7.1

CMake suite maintained and supported by Kitware (kitware.com/cmake).

我们以SGX SDK中给的SampleEnclave为例,对这个实例进行改写。

建立关键文件

文件的结构如下:

dck@dck-Precision-Tower-3620:~/SGX-develop/test-cmake$ tree SampleEnclave/
SampleEnclave/
├── App
│   ├── App.cpp
│   ├── App.h
│   ├── CMakeLists.txt
│   ├── Edger8rSyntax
│   │   ├── Arrays.cpp
│   │   ├── Functions.cpp
│   │   ├── Pointers.cpp
│   │   └── Types.cpp
│   ├── Enclave_u.c
│   ├── Enclave_u.h
│   ├── Enclave_u.o
│   └── TrustedLibrary
│       ├── Libc.cpp
│       ├── Libcxx.cpp
│       └── Thread.cpp
├── CMakeLists.txt
├── Enclave
│   ├── CMakeLists.txt
│   ├── config.01.xml
│   ├── config.02.xml
│   ├── config.03.xml
│   ├── config.04.xml
│   ├── Edger8rSyntax
│   │   ├── Arrays.cpp
│   │   ├── Arrays.edl
│   │   ├── Functions.cpp
│   │   ├── Functions.edl
│   │   ├── Pointers.cpp
│   │   ├── Pointers.edl
│   │   ├── Types.cpp
│   │   └── Types.edl
│   ├── Enclave.config.xml
│   ├── Enclave.cpp
│   ├── Enclave.edl
│   ├── Enclave.h
│   ├── Enclave.lds
│   ├── Enclave_private.pem
│   └── TrustedLibrary
│       ├── Libc.cpp
│       ├── Libc.edl
│       ├── Libcxx.cpp
│       ├── Libcxx.edl
│       ├── Thread.cpp
│       └── Thread.edl
├── Include
│   └── user_types.h
├── Makefile            //原makefile文件,我未删除
└── README.txt

7 directories, 42 files

首先在SampelEnclave,SampelEnclave/Enclave,SampelEnclave/App中建立CMakeLists.txt(注意,区分大小写)
首先写看SampelEnclave中的CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)             #确定版本号,必须步骤
project(HELLOENCLAVE)                           #项目名称,随便写
SET(SGX_SDK /opt/intel/sgxsdk)                  #SDK的安装路径
SET(SGX_MODE HW)                                #参数的设置,注意,如果给变量赋值的时候,值本身有空格,那么值需要使用“”来保证赋值的正确性,否则赋值可能存在错误
SET(SGX_ARCH x64)
SET(SGX_DEBUG 1)
SET(SGX_COMMON_CFLAGS -m64)
SET(SGX_LIBRARY_PATH ${SGX_SDK}/lib64)
SET(SGX_EDGER8R ${SGX_SDK}/bin/x64/sgx_edger8r)
SET(SGX_ENCLAVE_SIGNER ${SGX_SDK}/bin/x64/sgx_sign) #以上的参数都是根据自己的机器设置,注意不要设置错误
IF(SGX_DEBUG EQUAL 1)
   SET(SGX_COMMON_CFLAGS "${SGX_COMMON_CFLAGS} -O0 -g")
ELSE(SGX_DEBUG EQUAL 1)
   SET(SGX_COMMON_CFLAGS "${SGX_COMMON_CFLAGS} -O2")
ENDIF(SGX_DEBUG EQUAL 1)
#####################################################################
此处的是有待完善的,我想用CMakeLists.txt调用SDK中的对EDL文件处理的工具,但是只能够在build的时候才会使用,理想的状况是运行cmake ..的时候产生 *_t.*(可信)和*_u.*(不可信)文件,但是实际上在build的时候运行,就需要执行`cmake ..和make两遍`这里我是在终端使用指令产生了四个文件,具体命令后续再说
#MESSAGE(STATUS "SGX COMMON = ${SGX_COMMON_CFLAGS}")

#ADD_CUSTOM_COMMAND(OUTPUT Enclave_u.h Enclave_u.c
    #COMMAND ${SGX_EDGER8R} --untrusted ${CMAKE_CURRENT_SOURCE_DIR}/Enclave/Enclave.edl --search-path ${CMAKE_CURRENT_SOURCE_DIR}/Enclave --search-path ${SGX_SDK}/include
   # COMMENT "make ucode"
#)
#ADD_CUSTOM_TARGET(
    #ucode ALL
   # DEPENDS Enclave_u.h Enclave_u.c
#)
#ADD_CUSTOM_COMMAND(OUTPUT Enclave_t.h Enclave_t.c
    #COMMAND ${SGX_EDGER8R} --trusted ${CMAKE_CURRENT_SOURCE_DIR}/Enclave/Enclave.edl --search-#path ${CMAKE_CURRENT_SOURCE_DIR}/Enclave --search-path ${SGX_SDK}/include
    #COMMENT "make tcode"
#)
#ADD_CUSTOM_TARGET(
    #tcode ALL
   # DEPENDS Enclave_t.h Enclave_t.c
#)
add_subdirectory(App)                           #执行App文件夹中的CMakeLists.txt
add_subdirectory(Enclave)                       #执行Enclave文件夹中的CMakeLists.txt
########################################################################
同样的问题,使用手动签名
#ADD_CUSTOM_COMMAND(OUTPUT enclave.signed.so
    #COMMAND ${SGX_ENCLAVE_SIGNER} sign -key ${CMAKE_CURRENT_SOURCE_DIR}/Enclave/Enclave_private.pem -enclave ${CMAKE_CURRENT_SOURCE_DIR}/build/Enclave/libenclave.so -out ${CMAKE_CURRENT_SOURCE_DIR}/build/App/enclave.signed.so -config ${CMAKE_CURRENT_SOURCE_DIR}/Enclave/Enclave.config.xml
    #COMMENT "sign"
#)
#ADD_CUSTOM_TARGET(
   # sign ALL
    #DEPENDS enclave.signed.so
#)

SampleEnclave/App中的CMakeLists.txt文件内容如下:

SET(Urts_Library_Name sgx_urts)
FILE(GLOB_RECURSE App_Cpp_Files "*.cpp")   #将App文件夹中的cpp文件列表赋值给APP_CPP_FILES
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/Include ${PROJECT_SOURCE_DIR}/App ${SGX_SDK}/include)  #包含所需要的头文件,后面记得链接,相当于Makefile文件中“-L”选项
SET(App_C_Flags "${SGX_COMMON_CFLAGS} -fPIC -Wno-attributescmake")#设置编译App文件夹中C文件的文件选项
SET(App_C_Flags "${App_C_Flags} -DDEBUG -UNDEBUG -UEDEBUG")   #设置编译App文件夹中C文件的文件选项
SET(App_Cpp_Flags "${App_C_Flags}")                         #设置编译App文件夹中的CPP文件编译选项行
SET(App_Link_Flags "${SGX_COMMON_CFLAGS} -L/usr/lib -l${Urts_Library_Name} -lpthread -lsgx_uae_service")    #设置生成应用程序的链接选项,因为要用到SDK中带有的库
SET(CMAKE_CXX_FLAGS ${App_Cpp_Flags})         #将CMake中编译CPP文件中的编译选项设置成我们自己的选项
SET(CMAKE_C_FLAGS ${App_C_Flags})            #将将CMake中编译C文件中的编译选项设置成我们自己的选项
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${App_Link_Flags}")#设置链接生成可执行文件的时候的链接选项
SET(CMAKE_CXX_STANDARD 11)   #设置C++的std,相当于makefile文件中的-std=c++11
LINK_DIRECTORIES("/usr/lib")    #注意,不可信部分链接的库不再${SDK}/lib64中,而是在/usr/lib中,通过本条指令,这样在链接的时候,我们使用的库Cmake就会在/usr/lib中寻找
ADD_EXECUTABLE(main ${App_Cpp_Files} ../build/Enclave_u.c)#生成可执行文件,这里的可执行文件我们定义的名称是main
TARGET_LINK_LIBRARIES(main ${Urts_Library_Name} pthread sgx_uae_service) #可执行文件需要的库,注意链接库的先后顺序,有的库需要依赖前面的库函数,如果顺序错误,可能会报错,说找不到相应函数

SampleEnclave/Enclave中的CMakeLists.txt文件内容如下:

SET(Trts_Library_Name sgx_trts)
SET(Service_Library_Name sgx_tservice)
SET(Crypto_Library_Name sgx_tcrypto)
FILE(GLOB_RECURSE Enclave_Cpp_Files "*.cpp")
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/Include ${PROJECT_SOURCE_DIR}/Enclave ${SGX_SDK}/include ${SGX_SDK}/include/tlibc ${SGX_SDK}/include/libcxx)
SET(Enclave_C_Flags "${SGX_COMMON_CFLAGS} -nostdinc -fvisibility=hidden -fpie -ffunction-sections -fdata-sections -fstack-protector-strong")
SET(Enclave_Cpp_Flags "${Enclave_C_Flags} -std=c++11 -nostdinc++")
SET(Enclave_Link_Flags "${SGX_COMMON_CFLAGS} -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L${SGX_LIBRARY_PATH} -Wl,--whole-archive -l${Trts_Library_Name} -Wl,--no-whole-archive -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l${Crypto_Library_Name} -l${Service_Library_Name} -Wl,--end-group -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-pie,-eenclave_entry -Wl,--export-dynamic -Wl,--defsym,__ImageBase=0 -Wl,--gc-sections -Wl,--version-script=${PROJECT_SOURCE_DIR}/Enclave/Enclave.lds")#设置产生so文件的链接选项注意一下-Wl,--whole-archive -l${Trts_Library_Name} -Wl,--no-whole-archive -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -l${Crypto_Library_Name} -l${Service_Library_Name} -Wl,--end-group 这些部分,连接的时候要把sgx_trts库所有相关的都要连接上,不然会报上一大堆错误,后面的不需要全部链接相关的库,只需要链接对应的库即可在makefile中的原文如下:
# To generate a proper enclave, it is recommended to follow below guideline to link the trusted libraries:
#    1. Link sgx_trts with the `--whole-archive' and `--no-whole-archive' options,
#       so that the whole content of trts is included in the enclave.
#    2. For other libraries, you just need to pull the required symbols.
#       Use `--start-group' and `--end-group' to link these libraries.
# Do NOT move the libraries linked with `--start-group' and `--end-group' within `--whole-archive' and `--no-whole-archive' options.
# Otherwise, you may get some undesirable errors.
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_C_FLAGS ${Enclave_C_Flags})#设置Cmake编译C文件的编译选项
SET(CMAKE_CXX_FLAGS ${Enclave_Cpp_Flags})#设置CMake编译Cpp文件的编译选项
SET(CMAKE_SHARED_LINKER_FLAGS ${Enclave_Link_Flags})#设置共享库的链接选项
LINK_DIRECTORIES(${SGX_LIBRARY_PATH})#共享库链接其他库的时候的搜索路径,此处是SDK中提供的静态库
ADD_LIBRARY(enclave SHARED ${Enclave_Cpp_Files} ../build/Enclave_t.c)#生成libenclave.so
TARGET_LINK_LIBRARIES(enclave sgx_trts)#链接libenclave.so需要的库
TARGET_LINK_LIBRARIES(enclave  sgx_tcxx sgx_tstdc sgx_tcrypto sgx_tservice)#链接libenclave.so需要的库

上述文件已经写完,我们在SampleEnclave打开终端,分别输入以下命令

$ mkdir build
$ cd build
$ /opt/intel/sgxsdk/bin/x64/sgx_edger8r --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path /opt/intel/sgxsdk/include
$ /opt/intel/sgxsdk/bin/x64/sgx_edger8r --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path /opt/intel/sgxsdk/include

这样文件夹build中会生成四个文件 Enclave_t.h Enclave_t.c Enclave_u.h Enclave_u.c,之后我们需要更改SampleEnclave/App,SampleEnclave/Enclave中的每个cpp文件,让他们包含的头文件是我们生成的头文件,例如将App/App.cpp中的

#include "Enclave_u.h"

改为

#include "../build/Enclave_u.h"

不该的话也可以,只需要将生成的文件拷贝到相应的文件夹即可,保证文件能够找到根据edl文件产生的c文件,不然编译的时候会报错
之后我们继续在SampleEnclave/build执行命令:

$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/dck/SGX-develop/test-cmake/SampleEnclave/build

之后执行:

$ make
Scanning dependencies of target main
[  5%] Building CXX object App/CMakeFiles/main.dir/App.cpp.o
[ 10%] Building CXX object App/CMakeFiles/main.dir/Edger8rSyntax/Arrays.cpp.o
[ 15%] Building CXX object App/CMakeFiles/main.dir/Edger8rSyntax/Functions.cpp.o
[ 20%] Building CXX object App/CMakeFiles/main.dir/Edger8rSyntax/Pointers.cpp.o
[ 25%] Building CXX object App/CMakeFiles/main.dir/Edger8rSyntax/Types.cpp.o
[ 30%] Building CXX object App/CMakeFiles/main.dir/TrustedLibrary/Libc.cpp.o
[ 35%] Building CXX object App/CMakeFiles/main.dir/TrustedLibrary/Libcxx.cpp.o
[ 40%] Building CXX object App/CMakeFiles/main.dir/TrustedLibrary/Thread.cpp.o
[ 45%] Building C object App/CMakeFiles/main.dir/__/Enclave_u.c.o
[ 50%] Linking CXX executable main
[ 50%] Built target main
Scanning dependencies of target enclave
[ 55%] Building CXX object Enclave/CMakeFiles/enclave.dir/Edger8rSyntax/Arrays.cpp.o
[ 60%] Building CXX object Enclave/CMakeFiles/enclave.dir/Edger8rSyntax/Functions.cpp.o
[ 65%] Building CXX object Enclave/CMakeFiles/enclave.dir/Edger8rSyntax/Pointers.cpp.o
[ 70%] Building CXX object Enclave/CMakeFiles/enclave.dir/Edger8rSyntax/Types.cpp.o
[ 75%] Building CXX object Enclave/CMakeFiles/enclave.dir/Enclave.cpp.o
[ 80%] Building CXX object Enclave/CMakeFiles/enclave.dir/TrustedLibrary/Libc.cpp.o
[ 85%] Building CXX object Enclave/CMakeFiles/enclave.dir/TrustedLibrary/Libcxx.cpp.o
[ 90%] Building CXX object Enclave/CMakeFiles/enclave.dir/TrustedLibrary/Thread.cpp.o
[ 95%] Building C object Enclave/CMakeFiles/enclave.dir/__/Enclave_t.c.o
[100%] Linking CXX shared library libenclave.so
[100%] Built target enclave

这样我们就能在SampleEnclave/build/App中发现名称是main的应用程序,但是这个应用程序运行的时候会报错显示找不到enclave file,后面我们还需要将生成的libenclave.so使用SDK的签名工具进行签名,这样生成enclave.sign.so才能够让程序继续执行。我们执行以下命令:

$/opt/intel/sgxsdk/bin/x64/sgx_sign sign -key ../Enclave/Enclave_private.pem -enclave Enclave/libenclave.so -out App/enclave.signed.so -config ../Enclave/Enclave.config.xml

<EnclaveConfiguration>
    <ProdID>0ProdID>
    <ISVSVN>0ISVSVN>
    <StackMaxSize>0x40000StackMaxSize>
    <HeapMaxSize>0x100000HeapMaxSize>
    <TCSNum>10TCSNum>
    <TCSPolicy>1TCSPolicy>
    
    <DisableDebug>0DisableDebug>
    <MiscSelect>0MiscSelect>
    <MiscMask>0xFFFFFFFFMiscMask>
EnclaveConfiguration>
tcs_num 10, tcs_max_num 10, tcs_min_pool 1
The required memory is 4153344B.
Succeed.

之后我们看SampleEnclave/build/App文件夹中多了enclave.signed.so文件了,之后在SampleEnclave/build/App文件夹中运行

$ ./main
Checksum(0x0x7ffd3c5ed860, 100) = 0xfffd4143
Info: executing thread synchronization, please wait...  
Info: SampleEnclave successfully returned.
Enter a character before exit ...

我们看到,ENCLAVE已经正确的被建立,并且被争取的调用!至此,使用CMake就完成了,后续的时候可以将生成关键文件的指令放入CMakeLists.txt中,这样能一键完成编译。

你可能感兴趣的:(SGX,SGX,Cmake)