【SGX系列教程】(五)enclave多线程测试,以及EPC内存测试

文章目录

  • 一. 概述
  • 二. 原理分析
    • 2.1 多线程在Enclave中的实现流程
    • 2.2 多线程和EPC内存分配之间的冲突
    • 2.3 解决多线程和EPC内存分配冲突的策略
  • 三. 源码分析
    • 3.1 代码结构
    • 3.2 源码
      • 3.2.1 App文件夹
      • 3.2.2 Enclave文件夹
      • 3.2.3 Makefile
    • 3.3 总结
  • 四.感谢支持

一. 概述

    在Intel SGX环境下,多线程的实现主要依赖于SGX SDK提供的功能以及传统的线程库(如Pthreads)。本质上来说多线程是在Enclave外部创建的,然后每个线程分别调用ECALL进入Enclave执行。而直接在Enclave内部创建多线程并不被SGX直接支持,因为Enclave的设计初衷是为了保持安全性和隔离性,尽量减少复杂性。因此,传统的多线程管理(如线程创建、调度等)通常在外部进行,然后在Enclave内部利用这些外部线程来并行执行任务。

    尽管SGX本身不支持在Enclave内部直接创建线程,但可以通过以下方法来模拟这种效果:

  1. 通过多个ECALLs并行执行任务
  • 在外部创建多个线程,每个线程调用不同的ECALL来执行不同的任务。
  • 在Enclave内部,通过线程同步机制(如MutexCondition Variable)来管理这些任务。
  1. 线程池机制:
  • 在Host中实现一个线程池,预先创建多个线程,这些线程在需要时调用Enclave中的相应ECALL进行任务处理。

二. 原理分析

2.1 多线程在Enclave中的实现流程

  1. 线程上下文(Thread Context
    每个线程在进入Enclave时会创建一个新的线程上下文。SGX维护一个线程控制结构TCS),每个TCS与一个特定的线程绑定。这意味着每个进入Enclave的线程必须有一个相应的TCS。

  2. 线程控制结构(TCS
    TCS(Thread Control Structure)是Enclave的关键数据结构,用于管理线程上下文。
    在创建Enclave时,开发人员必须指定Enclave中允许的TCS数量(在Enclave.config.xml中设置,后面会讲)。这决定了可以同时在Enclave中执行的线程数量。

  3. ECALL与OCALL
    ECALL(Enclave Call):从Host调用进入Enclave的受保护函数。
    OCALL(Outside Call):从Enclave调用Host的外部函数。OCALL的实现通常涉及Host代码中的多线程处理。

  4. 线程同步
    Enclave提供了基本的线程同步原语,如互斥锁(Mutex)和条件变量(Condition Variable)。这些原语类似于Pthreads库中的相应功能,但实现上需要考虑安全性和性能。

2.2 多线程和EPC内存分配之间的冲突

  1. EPC(Enclave Page Cache)内存限制
    EPC是SGX的关键资源,用于存储Enclave的代码和数据。
    每个系统的EPC大小是有限的,典型大小为128MB(不包括系统预留和管理开销)。
  2. 多线程对EPC的影响
    每个线程进入Enclave都会消耗一定量的EPC内存,主要用于TCS线程堆栈
    多线程运行时,多个线程同时访问和分配EPC内存,这可能会导致EPC内存不足。
  3. EPC内存分配失败的原因
    内存碎片化:频繁的内存分配和释放可能导致EPC内存碎片化,虽然总内存可能足够,但无法找到连续的内存块进行分配。
    线程堆栈大小:每个线程的堆栈大小设置过大可能导致EPC内存快速消耗。
    并发内存分配:多线程同时分配大量内存时,可能会导致EPC内存分配冲突。

2.3 解决多线程和EPC内存分配冲突的策略

  1. 减少线程数量
    尽量减少同时在Enclave中运行的线程数量。
    优化TCS数量,确保足够但不浪费。
  2. 优化内存分配
    内存池:使用内存池技术预先分配和管理内存,减少碎片化。
    内存复用:重用已经分配的内存,减少频繁的分配和释放操作。
  3. 调整堆栈和堆大小
    根据应用需求合理设置堆栈和堆的大小(在Enclave.config.xml中设置,后面会讲),避免过大的默认值。
    在Enclave配置文件中合理配置堆栈和堆大小。

三. 源码分析

3.1 代码结构

multi_enclave_thread/
├── App
│   ├── App.cpp
│   └── App.h
│   ├── ErrorSupport.cpp
│   └── ErrorSupport.h
│   └── Thread.cpp              # 多线程主程序
├── Enclave
│   ├── Enclave.config.xml      # 配置文件
│   ├── Enclave.cpp
│   ├── Enclave.edl
│   ├── Thread.cpp              # 多线程ecall程序
│   ├── Thread.edl              # 多线程ecall函数接口
│   ├── Enclave.h
│   ├── Enclave.lds
│   └── Enclave_private.pem
├── Include
└── Makefile

3.2 源码

3.2.1 App文件夹

  • App.cpp
#include <stdio.h>
#include <string.h>
#include <vector>
#include <thread>
#include <iostream>
#include "sgx_urts.h"
#include "App.h"
#include "Enclave_u.h"
#include "ErrorSupport.h"#define MAX_PATH FILENAME_MAX/* Global EID shared by multiple threads */
sgx_enclave_id_t global_eid = 0;/* OCall函数,给ECALL函数调用,打印输出 */
void ocall_print_string(const char *str)
{printf("%s", str); /* 代理将会检查字符串的长度并在结尾添加空字符,防止缓冲区溢出 */
}// 定义OCALL,延时us
void ocall_host_sleep_microseconds(int microseconds) {std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
}
// 定义OCALL,延时ms
void ocall_host_sleep_milliseconds(int milliseconds) {std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}/* 应用程序入口 */
int SGX_CDECL main(int argc, char *argv[])
{(void)(argc);(void)(argv);// 调用 sgx_create_enclave 创建一个 Enclave 实例sgx_status_t ret = SGX_ERROR_UNEXPECTED;   // 定义函数返回值ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL); if (ret != SGX_SUCCESS) {printf("创建enclave失败, 错误码为: %d\n", ret);ret_error_support(ret);   // 打印具体的错误信息return -1;}// 测试1,2: 多线程下生产者、消费者测试,主要用到mutex互斥锁和cond信号量ecall_thread_functions();       // 测试3: 多线程下内存消耗测试test_memory_consumption(1);    // 单线程测试// test_memory_consumption(2); // 2线程测试// test_memory_consumption(4); // 4线程测试// test_memory_consumption(5); // 8线程测试/* 销毁 Enclave */sgx_destroy_enclave(global_eid);return 0;
}
  • App.h
#ifndef _APP_H_
#define _APP_H_#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "sgx_error.h"       /* sgx_status_t */
#include "sgx_eid.h"     /* sgx_enclave_id_t */
#include <cstdio>   // Add this line for printf and getchar#ifndef TRUE
# define TRUE 1
#endif#ifndef FALSE
# define FALSE 0
#endif# define TOKEN_FILENAME   "enclave.token"
# define ENCLAVE_FILENAME "enclave.signed.so"extern sgx_enclave_id_t global_eid;    /* global enclave id */#if defined(__cplusplus)
extern "C" {
#endifvoid ecall_thread_functions(void);
void test_memory_consumption(int num_threads);#if defined(__cplusplus)
}
#endif#endif /* !_APP_H_ */
  • Thread.cpp
#include <thread>        // 包含标准C++线程库头文件
#include <iostream>      // 包含标准C++线程库头文件
#include <vector>        // 包含标准C++线程库头文件
#include <stdio.h>       // 包含标准输入输出头文件
#include "App.h"         // 包含应用程序的头文件
#include "Enclave_u.h"   // 包含Enclave生成的头文件,用于与Enclave进行交互using namespace std;     // 使用标准命名空间/*******************************测试1:多线程互斥锁、信号量测试****************************************/
static size_t counter = 0;  // 全局计数器
/* 增加计数器的函数 */
void increase_counter(void)
{size_t cnr = 0;sgx_status_t ret = SGX_ERROR_UNEXPECTED;ret = ecall_increase_counter(global_eid, &cnr);  // 调用ECALL增加计数器if (cnr != 0) counter = cnr;                     // 如果cnr不为0,更新全局计数器if (ret != SGX_SUCCESS)abort();  // 如果调用失败,终止程序
}
/* 数据生产者函数 */
void data_producer(void)
{sgx_status_t ret = SGX_ERROR_UNEXPECTED;ret = ecall_producer(global_eid);  // 调用ECALL数据生产者if (ret != SGX_SUCCESS)abort();  // 如果调用失败,终止程序
}
/* 数据消费者函数 */
void data_consumer(void)
{sgx_status_t ret = SGX_ERROR_UNEXPECTED;ret = ecall_consumer(global_eid);  // 调用ECALL数据消费者if (ret != SGX_SUCCESS)abort();  // 如果调用失败,终止程序
}/* ecall_thread_functions:* 调用线程函数,包括互斥锁、条件变量等。*/
void ecall_thread_functions(void)
{// 创建和启动四个增加计数器的线程thread adder1(increase_counter);thread adder2(increase_counter);thread adder3(increase_counter);thread adder4(increase_counter);// 等待所有线程完成,回收线程adder1.join();adder2.join();adder3.join();adder4.join();if(counter == 4 * LOOPS_PER_THREAD)std::cout<<"多线程计数器测试通过<(^-^)>"<<std::endl;elsestd::cout<<"多线程计数器测试不通过/(ㄒoㄒ)/~~"<<std::endl;// 确认计数器的值是否符合预期assert(counter == 4 * LOOPS_PER_THREAD);// 创建和启动消费和生产线程thread consumer1(data_consumer);thread producer0(data_producer);thread consumer2(data_consumer);thread consumer3(data_consumer);thread consumer4(data_consumer);// 等待所有线程完成,回收线程consumer1.join();consumer2.join();consumer3.join();consumer4.join();producer0.join();
}/*******************************测试2:多线程内存消耗测试****************************************/
// 线程具体执行函数,其中thread_num表示开启的线程数,而times表示当前调用的线程号
void thread_task(sgx_enclave_id_t eid, int thread_num,int times) {ecall_thread_test(eid,thread_num,times);
}
// 测试多线程调用ecall函数,也就是在REE中开了多线程,各个线程分别调用ecall函数
void test_memory_consumption(int num_threads) {std::vector<std::thread> threads;auto start = std::chrono::high_resolution_clock::now();  // 计算起始时间// 开启多线程执行,传入的是具体的线程函数、enclave id、当前的线程数(为了给不同的线程数下分配不同内存大小)、当前线程号for (int i = 1; i <= num_threads; ++i) {threads.emplace_back(thread_task, global_eid, num_threads, i);}// 多线程回收for (auto& t : threads) {t.join();}auto end = std::chrono::high_resolution_clock::now();   // 计算结束时间auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << "Time taken with " << num_threads << " threads: " << duration.count() << " ms." << std::endl;
}

3.2.2 Enclave文件夹

  • Enclave.config.xml
<EnclaveConfiguration><ProdID>0</ProdID>                      <!-- 生产者ID,通常用于标识该Enclave所属的产品。这在调试和开发阶段通常为0 --><ISVSVN>0</ISVSVN>                      <!-- 软件版本号,用于标识当前Enclave的版本号。通常用于版本管理和更新控制 --><StackMaxSize>0x40000</StackMaxSize>    <!-- 最大栈空间大小:256KB, 可根据需求调整 --><HeapMaxSize>0x8000000</HeapMaxSize>    <!-- 最大堆空间大小:128MB --><TCSNum>10</TCSNum>                     <!-- 线程控制结构(TCS)的数量,设置为10,TCS用于管理Enclave中的线程 --><TCSPolicy>1</TCSPolicy>                <!-- TCS策略,1表示允许动态分配 --><!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release --><DisableDebug>0</DisableDebug>          <!-- 调试开关,0表示启用调试,1表示禁用调试。调试阶段通常设置为0,发布阶段建议设置为1 -->      <MiscSelect>0</MiscSelect>              <!-- 杂项选择,0表示不选择任何杂项功能 -->  <MiscMask>0xFFFFFFFF</MiscMask>         <!-- 杂项掩码,0xFFFFFFFF表示启用所有可用的杂项功能 -->  
</EnclaveConfiguration>     
  • Enclave.cpp
#include "Enclave.h"
#include "Enclave_t.h"  /* print_string */
#include "sgx_trts.h"
#include <stdio.h>      /* vsnprintf */
#include <string.h>
#include <vector>   
#include <string>// Invokes OCALL to display the enclave buffer to the terminal.
int printf(const char* fmt, ...)
{char buf[BUFSIZ] = { '\0' };va_list ap;va_start(ap, fmt);vsnprintf(buf, BUFSIZ, fmt, ap);va_end(ap);ocall_print_string(buf);return (int)strnlen(buf, BUFSIZ - 1) + 1;
}
  • Enclave.h
#ifndef _ENCLAVE_H_
#define _ENCLAVE_H_
int printf(const char* fmt, ...);
#endif
  • Thread.cpp
#include "Enclave.h"
#include "Enclave_t.h"
#include "sgx_thread.h"
#include <vector>
#include <algorithm>/********************************************测试1:多线程计数器测试,主要测试mutex互斥锁***************************************************/
static size_t global_counter = 0; // 全局计数器
static sgx_thread_mutex_t global_mutex = SGX_THREAD_MUTEX_INITIALIZER; // 全局互斥锁
/** ecall_increase_counter: 增加计数至LOOPS_PER_THREAD*   在enclave中使用线程API。*/
size_t ecall_increase_counter(void)
{size_t ret = 0;for (int i = 0; i < LOOPS_PER_THREAD; i++) {sgx_thread_mutex_lock(&global_mutex);   // 加锁/* 互斥地增加计数器 */size_t tmp = global_counter;global_counter = ++tmp;if (4*LOOPS_PER_THREAD == global_counter)ret = global_counter;sgx_thread_mutex_unlock(&global_mutex); // 解锁}return ret;
}/*******************************测试1,2:多线程下生产者、消费者测试,主要用到mutex互斥锁和cond信号量*****************************************/
#define BUFFER_SIZE 50 // 缓冲区大小typedef struct {int buf[BUFFER_SIZE];       // 缓冲区数组int occupied;               // 已占用的缓冲区数量int nextin;                 // 下一个写入位置int nextout;                // 下一个读取位置sgx_thread_mutex_t mutex;   // 互斥锁sgx_thread_cond_t more;     // 条件变量,表示有更多数据sgx_thread_cond_t less;     // 条件变量,表示有更少数据
} cond_buffer_t;// 定义一个全局变量,供producer和consumer共用
static cond_buffer_t buffer = {{0, 0, 0, 0, 0, 0}, 0, 0, 0,SGX_THREAD_MUTEX_INITIALIZER, SGX_THREAD_COND_INITIALIZER, SGX_THREAD_COND_INITIALIZER}; // 初始化缓冲区// 生产者线程调用:生产4*LOOPS_PER_THREAD个消息
void ecall_producer(void)
{for (int i = 0; i < 4*LOOPS_PER_THREAD; i++) {cond_buffer_t *b = &buffer;sgx_thread_mutex_lock(&b->mutex);   // 加锁while (b->occupied >= BUFFER_SIZE)sgx_thread_cond_wait(&b->less, &b->mutex); // 等待缓冲区有空闲空间b->buf[b->nextin] = b->nextin;      // 写入数据b->nextin++;b->nextin %= BUFFER_SIZE;   // 循环使用缓冲区b->occupied++;              // 增加占用计数sgx_thread_cond_signal(&b->more); // 通知消费者有更多数据sgx_thread_mutex_unlock(&b->mutex); // 解锁}
}// 消费者线程调用:消费LOOPS_PER_THREAD个消息
void ecall_consumer(void)
{for (int i = 0; i < LOOPS_PER_THREAD; i++) {cond_buffer_t *b = &buffer;         // 使用全局变量sgx_thread_mutex_lock(&b->mutex);   // 加锁while(b->occupied <= 0)sgx_thread_cond_wait(&b->more, &b->mutex); // 等待缓冲区有数据b->buf[b->nextout++] = 0;                      // 读取数据b->nextout %= BUFFER_SIZE;  // 循环使用缓冲区b->occupied--;              // 减少占用计数sgx_thread_cond_signal(&b->less); // 通知生产者有空闲空间sgx_thread_mutex_unlock(&b->mutex); // 解锁}
}/********************************************测试3:多线程下内存消耗测试***************************************************/
const size_t TOTAL_MEMORY = 96 * 1024 * 1024;   // 总的分配内存 96MB
const size_t CHUNK_SIZE = 256 * 1024;           // 一次性malloc分配的块大小 256KB// 具体执行函数
void memory_intensive_multi_thread(size_t thread_num,int times) {size_t total_memory_to_assign = TOTAL_MEMORY / thread_num;        // 计算需要分配的总内存大小size_t num_chunks = total_memory_to_assign / CHUNK_SIZE;          // 计算CHUNK的数量std::vector<unsigned char*> allocated_chunks;for (size_t i = 0; i < num_chunks; ++i) {unsigned char* ptr;       while((ptr=(unsigned char*)malloc(CHUNK_SIZE))==nullptr)      // 分配CHUNK_SIZE大小内存空间给ptr{printf("内存分配失败...\n");ocall_host_sleep_milliseconds(10);  // 延时10ms}if (ptr != nullptr) {                                          // 分配成功memset(ptr, 0x12, CHUNK_SIZE);allocated_chunks.push_back(ptr);// printf("第%d进程,第%d块,分配内存大小: %d KB, 内存值:\n",times,i,CHUNK_SIZE/1024); ocall_host_sleep_milliseconds(1);  // 延时1ms,模拟enclave中的计算任务} else {printf("内存分配失败!\n");} }for (unsigned char* ptr : allocated_chunks) {free(ptr);}
}// thread_num表示当前的线程数,times表示第几个线程的运行
void ecall_thread_test(int thread_num,int times) {printf("enclave线程%d运行中....\n",times);memory_intensive_multi_thread(thread_num,times);printf("enclave线程%d运行结束....\n",times);
}
  • Thread.edl
enclave {from "sgx_tstdc.edl" import sgx_thread_wait_untrusted_event_ocall, sgx_thread_set_untrusted_event_ocall, sgx_thread_setwait_untrusted_events_ocall, sgx_thread_set_multiple_untrusted_events_ocall;trusted {/** Use SGX mutex.*/public size_t ecall_increase_counter();/** Use SGX condition variables.*/public void ecall_producer();public void ecall_consumer();public void ecall_thread_test(int thread_num,int times);};
};
  • Enclave.edl
enclave {include "user_types.h" /* buffer_t */from "Thread.edl" import *;trusted {};untrusted {void ocall_print_string([in, string] const char *str);void ocall_host_sleep_microseconds(int microseconds);void ocall_host_sleep_milliseconds(int milliseconds);};
};

3.2.3 Makefile

######## SGX SDK Settings ########
# 设置 SGX SDK 的路径、模式、架构和调试选项
# SGX SDK 安装路径
SGX_SDK ?= /opt/intel/sgxsdk
# SGX 模式:硬件模式(HW)
SGX_MODE ?= HW
# SGX 架构:64 位(x64)
SGX_ARCH ?= x64
# SGX 调试模式:启用(1)
SGX_DEBUG ?= 1# 判断系统的位数,如果是 32 位,设置架构为 x86
ifeq ($(shell getconf LONG_BIT), 32)SGX_ARCH := x86
# 如果编译器标志中包含 -m32,也设置架构为 x86
else ifeq ($(findstring -m32, $(CXXFLAGS)), -m32)SGX_ARCH := x86
endif# 根据架构选择编译器标志、库路径和工具路径
ifeq ($(SGX_ARCH), x86)SGX_COMMON_FLAGS := -m32                         # 设置 32 位编译标志SGX_LIBRARY_PATH := $(SGX_SDK)/lib               # 32 位库路径SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x86/sgx_sign # 使用 32 位签名工具SGX_EDGER8R := $(SGX_SDK)/bin/x86/sgx_edger8r     # 使用 32 位 Edger8r 工具
elseSGX_COMMON_FLAGS := -m64                         # 设置 64 位编译标志SGX_LIBRARY_PATH := $(SGX_SDK)/lib64             # 64 位库路径SGX_ENCLAVE_SIGNER := $(SGX_SDK)/bin/x64/sgx_sign # 使用 64 位签名工具SGX_EDGER8R := $(SGX_SDK)/bin/x64/sgx_edger8r     # 使用 64 位 Edger8r 工具
endif# 检查是否同时设置了调试模式和预发布模式
ifeq ($(SGX_DEBUG), 1)
ifeq ($(SGX_PRERELEASE), 1)
$(error Cannot set SGX_DEBUG and SGX_PRERELEASE at the same time!!)
# 如果两个都设置了,报错 "不能同时设置调试模式和预发布模式"
endif
endif# 根据是否启用调试模式设置编译标志
ifeq ($(SGX_DEBUG), 1)SGX_COMMON_FLAGS += -O0 -g  # 调试模式:不进行优化,包含调试信息
elseSGX_COMMON_FLAGS += -O2    # 生产模式:优化代码
endif# 设置更多的编译器警告标志,确保代码质量
SGX_COMMON_FLAGS += -Wall -Wextra -Winit-self -Wpointer-arith -Wreturn-type \-Waddress -Wsequence-point -Wformat-security \-Wmissing-include-dirs -Wfloat-equal -Wundef -Wshadow \-Wcast-align -Wcast-qual -Wconversion -Wredundant-decls
SGX_COMMON_CFLAGS := $(SGX_COMMON_FLAGS) -Wjump-misses-init -Wstrict-prototypes -Wunsuffixed-float-constants # C 编译标志
SGX_COMMON_CXXFLAGS := $(SGX_COMMON_FLAGS) -Wnon-virtual-dtor -std=c++11  # C++ 编译标志,使用 C++11 标准######## App Settings ######### 应用程序设置
ifneq ($(SGX_MODE), HW)Urts_Library_Name := sgx_urts_sim  # 如果不是硬件模式,使用仿真库
elseUrts_Library_Name := sgx_urts      # 如果是硬件模式,使用真实库
endif# 指定应用程序的源文件和包含路径
App_Cpp_Files := $(wildcard App/*.cpp)
App_Include_Paths := -IInclude -IApp -I$(SGX_SDK)/include# 设置应用程序的编译标志
App_C_Flags := -fPIC -Wno-attributes $(App_Include_Paths)# 根据不同的配置模式,设置不同的宏定义
# Three configuration modes - Debug, prerelease, release
#   Debug - Macro DEBUG enabled.
#   Prerelease - Macro NDEBUG and EDEBUG enabled.
#   Release - Macro NDEBUG enabled.
ifeq ($(SGX_DEBUG), 1)App_C_Flags += -DDEBUG -UNDEBUG -UEDEBUG
else ifeq ($(SGX_PRERELEASE), 1)App_C_Flags += -DNDEBUG -DEDEBUG -UDEBUG
elseApp_C_Flags += -DNDEBUG -UEDEBUG -UDEBUG
endifApp_Cpp_Flags := $(App_C_Flags)
App_Link_Flags := -L$(SGX_LIBRARY_PATH) -l$(Urts_Library_Name) -lpthread # 生成对象文件的规则
App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o)
# 指定生成的应用程序名称
App_Name := app######## Enclave Settings ########
# 设置信任域版本脚本文件根据调试模式与硬件模式判断
Enclave_Version_Script := Enclave/Enclave.lds
ifeq ($(SGX_MODE), HW)
ifneq ($(SGX_DEBUG), 1)
ifneq ($(SGX_PRERELEASE), 1)# 硬件发布模式下使用的版本脚本文件# Choose to use 'Enclave.lds' for HW release modeEnclave_Version_Script = Enclave/Enclave.lds 
endif
endif
endif# 仿真模式与硬件模式下使用不同的库
ifneq ($(SGX_MODE), HW)Trts_Library_Name := sgx_trts_sim      # 仿真模式库Service_Library_Name := sgx_tservice_sim # 仿真模式服务库
elseTrts_Library_Name := sgx_trts         # 硬件模式库Service_Library_Name := sgx_tservice  # 硬件模式服务库
endif
Crypto_Library_Name := sgx_tcrypto        # 加密库# 指定信任域的源文件和包含路径
Enclave_Cpp_Files := $(wildcard Enclave/*.cpp)
Enclave_Include_Paths := -IInclude -IEnclave -I$(SGX_SDK)/include -I$(SGX_SDK)/include/libcxx -I$(SGX_SDK)/include/tlibc # 设置信任域的编译标志
Enclave_C_Flags := -nostdinc -fvisibility=hidden -fpie -fstack-protector -fno-builtin-printf $(Enclave_Include_Paths)
Enclave_Cpp_Flags := $(Enclave_C_Flags) -nostdinc++# 启用安全链接选项
Enclave_Security_Link_Flags := -Wl,-z,relro,-z,now,-z,noexecstack# 生成信任域的正确链接规则
# 按步骤链接信任库
Enclave_Link_Flags := $(Enclave_Security_Link_Flags) \-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,--version-script=$(Enclave_Version_Script)
# 指定信任域生成的对象文件
Enclave_Cpp_Objects := $(Enclave_Cpp_Files:.cpp=.o)
# 指定生成的信任域库名
Enclave_Name := enclave.so
Signed_Enclave_Name := enclave.signed.so
# 配置文件和测试密钥文件
Enclave_Config_File := Enclave/Enclave.config.xml
Enclave_Key := Enclave/Enclave_private.pem# 生成不同的构建模式名称
ifeq ($(SGX_MODE), HW)
ifeq ($(SGX_DEBUG), 1)Build_Mode = HW_DEBUG
else ifeq ($(SGX_PRERELEASE), 1)Build_Mode = HW_PRERELEASE
elseBuild_Mode = HW_RELEASE
endif
else
ifeq ($(SGX_DEBUG), 1)Build_Mode = SIM_DEBUG
else ifeq ($(SGX_PRERELEASE), 1)Build_Mode = SIM_PRERELEASE
elseBuild_Mode = SIM_RELEASE
endif
endif.PHONY: all run target
all: .config_$(Build_Mode)_$(SGX_ARCH)@$(MAKE) targetifeq ($(Build_Mode), HW_RELEASE)
target: $(App_Name) $(Enclave_Name)@echo "The project has been built in release hardware mode."@echo "Please sign the $(Enclave_Name) first with your signing key before you run the $(App_Name) to launch and access the enclave."@echo "To sign the enclave use the command:"@echo "   $(SGX_ENCLAVE_SIGNER) sign -key <your key> -enclave $(Enclave_Name) -out <$(Signed_Enclave_Name)> -config $(Enclave_Config_File)"@echo "You can also sign the enclave using an external signing tool."@echo "To build the project in simulation mode set SGX_MODE=SIM. To build the project in prerelease mode set SGX_PRERELEASE=1 and SGX_MODE=HW."
else
target: $(App_Name) $(Signed_Enclave_Name)
ifeq ($(Build_Mode), HW_DEBUG)@echo "The project has been built in debug hardware mode."
else ifeq ($(Build_Mode), SIM_DEBUG)@echo "The project has been built in debug simulation mode."
else ifeq ($(Build_Mode), HW_PRERELEASE)@echo "The project has been built in pre-release hardware mode."
else ifeq ($(Build_Mode), SIM_PRERELEASE)@echo "The project has been built in pre-release simulation mode."
else@echo "The project has been built in release simulation mode."
endif
endif# 运行目标规则,首先构建所有目标,然后运行应用程序,除非是在硬件发布模式下。
run: all
ifneq ($(Build_Mode), HW_RELEASE)@$(CURDIR)/$(App_Name)@echo "RUN  =>  $(App_Name) [$(SGX_MODE)|$(SGX_ARCH), OK]"
endif# 配置文件生成规则,如果构建模式和架构改变,重新生成配置
.config_$(Build_Mode)_$(SGX_ARCH):@rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.*@touch .config_$(Build_Mode)_$(SGX_ARCH)######## App Objects ######### 生成 Enclave_u.h,如果 Enclave.edl 改变
App/Enclave_u.h: $(SGX_EDGER8R) Enclave/Enclave.edl@cd App && $(SGX_EDGER8R) --untrusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include@echo "GEN  =>  $@"App/Enclave_u.c: App/Enclave_u.h# 编译 Enclave_u.c 生成对象文件
App/Enclave_u.o: App/Enclave_u.c@$(CC) $(SGX_COMMON_CFLAGS) $(App_C_Flags) -c $< -o $@@echo "CC   <=  $<"# 编译应用程序源文件生成对象文件
App/%.o: App/%.cpp App/Enclave_u.h@$(CXX) $(SGX_COMMON_CXXFLAGS) $(App_Cpp_Flags) -c $< -o $@@echo "CXX  <=  $<"# 链接对象文件生成应用程序可执行文件
$(App_Name): App/Enclave_u.o $(App_Cpp_Objects)@$(CXX) $^ -o $@ $(App_Link_Flags)@echo "LINK =>  $@"######## Enclave Objects ########
# 生成 Enclave_t.h,如果 Enclave.edl 改变
Enclave/Enclave_t.h: $(SGX_EDGER8R) Enclave/Enclave.edl@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl --search-path ../Enclave --search-path $(SGX_SDK)/include@echo "GEN  =>  $@"Enclave/Enclave_t.c: Enclave/Enclave_t.h# 编译 Enclave_t.c 生成对象文件
Enclave/Enclave_t.o: Enclave/Enclave_t.c@$(CC) $(SGX_COMMON_CFLAGS) $(Enclave_C_Flags) -c $< -o $@@echo "CC   <=  $<"# 编译信任域源文件生成对象文件
Enclave/%.o: Enclave/%.cpp@$(CXX) $(SGX_COMMON_CXXFLAGS) $(Enclave_Cpp_Flags) -c $< -o $@@echo "CXX  <=  $<"# 生成信任域对象文件
$(Enclave_Cpp_Objects): Enclave/Enclave_t.h# 链接对象文件生成信任域共享库文件
$(Enclave_Name): Enclave/Enclave_t.o $(Enclave_Cpp_Objects)@$(CXX) $^ -o $@ $(Enclave_Link_Flags)@echo "LINK =>  $@"# 使用测试私钥签名信任域共享库文件
$(Signed_Enclave_Name): $(Enclave_Name)
ifeq ($(wildcard $(Enclave_Key)),)@echo "There is no enclave test key<Enclave_private_test.pem>."@echo "The project will generate a key<Enclave_private_test.pem> for test."@openssl genrsa -out $(Enclave_Key) -3 3072
endif@$(SGX_ENCLAVE_SIGNER) sign -key $(Enclave_Key) -enclave $(Enclave_Name) -out $@ -config $(Enclave_Config_File)@echo "SIGN =>  $@"# clean 目标,删除生成的文件
.PHONY: cleanclean:@rm -f .config_* $(App_Name) $(Enclave_Name) $(Signed_Enclave_Name) $(App_Cpp_Objects) App/Enclave_u.* $(Enclave_Cpp_Objects) Enclave/Enclave_t.*

3.3 总结

    在SGX中,直接在Enclave内部创建线程是不被支持的。我们可以通过在App中创建多线程,并利用ECALL机制在Enclave中执行并行任务来模拟这种效果。通过合理的线程同步机制和资源管理,可以有效地在Enclave中实现多线程并行处理。

四.感谢支持

    完结撒花!后续将持续输出,形成Intel SGX的系列教程,并结合密码学算法设计更复杂功能。希望看到这里的小伙伴能点个关注,也欢迎志同道合的小伙伴一起广泛交流。
    码字实属不易,如果本文对你有10分帮助,就赏个10分把,感谢各位大佬支持!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/374080.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS(43) @BuilderParam标签使用指南

BuilderParam BuilderParam使用举例定义模板定义具体实现BuilderParam初始化 demo源码参考资料 BuilderParam 该标签有的作用有点类似于设计模式中的模板模式&#xff0c;类似于指定一个UI占位符&#xff0c;具体的实现交给具体的Builder&#xff0c;顾名思义&#xff0c;可以…

【算法】排序算法介绍 附带C#和Python实现代码

1. 冒泡排序(Bubble Sort) 2. 选择排序(Selection Sort) 3. 插入排序(Insertion Sort) 4. 归并排序(Merge Sort) 5. 快速排序(Quick Sort) 排序算法是计算机科学中的一个基础而重要的部分,用于将一组数据按照一定的顺序排列。下面介绍几种常见的排序算法,…

可控学习综述:信息检索中的方法、应用和挑战

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

YOLOv10改进 | Conv篇 | 利用YOLO-MS的MSBlock轻量化网络结构(既轻量又长点)

一、本文介绍 本文给大家带来的改进机制是利用YOLO-MS提出的一种针对于实时目标检测的MSBlock模块(其其实不能算是Conv但是其应该是一整个模块)&#xff0c;我们将其用于C2f中组合出一种新的结构&#xff0c;来替换我们网络中的模块可以达到一种轻量化的作用&#xff0c;我将其…

【Python基础】代码如何打包成exe可执行文件

本文收录于 《一起学Python趣味编程》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、安装PyInstaller三、使用PyInstaller打包四、验证打包是否成功五、总结 一、前言 本文介绍如何…

SFUZZ模糊测试平台全新升级,从标准到实践助力车企安全出海

开源网安模糊测试平台SFuzz全新升级&#xff0c;参照各国相关标准要求进行针对性建设&#xff0c;可为智能网联汽车信息安全测试提供更为强大的工具支持。SFuzz向被测系统输入大量随机数据&#xff0c;模拟各种异常情况&#xff0c;可以发现被测系统内潜在的缺陷和漏洞&#xf…

ChatGPT提问获取高质量答案的艺术PDF下载书籍推荐分享

ChatGPT高质量prompt技巧分享pdf&#xff0c; ChatGPT提问获取高质量答案的艺术pdf。本书是一本全面的指南&#xff0c;介绍了各种 Prompt 技术的理解和利用&#xff0c;用于从 ChatGPTmiki sharing中生成高质量的答案。我们将探讨如何使用不同的 Prompt 工程技术来实现不同的目…

C语言——结构体

一、定义和使用结构体 1.1概述 前面我们见过的数据类型&#xff0c;比如int,float,char等是在程序中简单的使用&#xff0c;如果我们要根据自己的需求来建立一些复杂的数据&#xff0c;就需要用到结构体。 例如&#xff0c;一个学生的学号&#xff0c;姓名&#xff0c;性别&am…

Python 利用pandas处理CSV文件(DataFrame的基础用法)

前面介绍过通过Python标准库中的CSV模块处理CSV文件&#xff1a; Python 利用CSV模块处理数据 相比CSV模块&#xff0c;pandas的功能更加强大&#xff0c;本文将简单介绍如何通过pandas来处理CSV文件。 文章目录 一、pandas简介二、用法示例2.1 读取CSV文件2.1.1 read_csv参数…

Python 视频的色彩转换

这篇教学会介绍使用OpenCV 的cvtcolor() 方法&#xff0c;将视频的色彩模型从RGB 转换为灰阶、HLS、HSV...等。 因为程式中的OpenCV 会需要使用镜头或GPU&#xff0c;所以请使用本机环境( 参考&#xff1a;使用Python 虚拟环境) 或使用Anaconda Jupyter 进行实作( 参考&#x…

火柴棒图python绘画

使用Python绘制二项分布的概率质量函数&#xff08;PMF&#xff09; 在这篇博客中&#xff0c;我们将探讨如何使用Python中的scipy库和matplotlib库来绘制二项分布的概率质量函数&#xff08;PMF&#xff09;。二项分布是统计学中常见的离散概率分布&#xff0c;描述了在固定次…

MUNIK解读ISO26262--系统架构

功能安全之系统阶段-系统架构 我们来浅析下功能安全系统阶段重要话题——“系统架构” 目录概览&#xff1a; 系统架构的作用系统架构类型系统架构层级的相关安全机制梳理 1.系统架构的作用 架构的思维包括抽象思维、分层思维、结构化思维和演化思维。通过将复杂系统分解…

OZON生活家居用品爆款新品

OZON生活家居用品爆款新品涵盖了多个方面&#xff0c;这些产品不仅满足了消费者对生活品质的追求&#xff0c;也反映了当前市场的热门趋势。以下是一些在OZON平台上备受关注的生活家居用品爆款新品&#xff1a; OZON生活家居用品爆款新品工具&#xff1a;D。DDqbt。COm/74rD T…

昇思25天学习打卡营第17天|基于MobileNetv2的垃圾分类

今天学习的内容是利用视觉图像技术&#xff0c;来实现垃圾分类代码开发的方法。通过读取本地图像数据作为输入&#xff0c;对图像中的垃圾物体进行检测&#xff0c;并且将检测结果图片保存到文件中。 本章节主要包括8部分内容&#xff1a; 1、实验目的 1、了解熟悉垃圾分类应用…

防御笔记第四天(持续更新)

1.状态检测技术 检测数据包是否符合协议的逻辑顺序&#xff1b;检查是否是逻辑上的首包&#xff0c;只有首包才会创建会话表。 状态检测机制可以选择关闭或则开启 [USG6000V1]firewall session link-state tcp ? check Indicate link state check [USG6000V1]firewall ses…

实践致知第12享:如何新建一个Word并设置格式

一、背景需求 小姑电话说&#xff1a;要新建一个Word文档&#xff0c;并将每段的首行设置空2格。 二、解决方案 1、在电脑桌面上空白地方&#xff0c;点击鼠标右键&#xff0c;在下拉的功能框中选择“DOC文档”或“DOCX文档”都可以&#xff0c;如下图所示。 之后&#xff0…

光学传感器图像处理流程(二)

光学传感器图像处理流程&#xff08;二&#xff09; 2.4. 图像增强2.4.1. 彩色合成2.4.2 直方图变换2.4.3. 密度分割2.4.4. 图像间运算2.4.5. 邻域增强2.4.6. 主成分分析2.4.7. 图像融合 2.5. 裁剪与镶嵌2.5.1. 图像裁剪2.5.2. 图像镶嵌 2.6. 遥感信息提取2.6.1. 目视解译2.6.2…

沙龙回顾|MongoDB如何充当企业开发加速器?

数据不仅是企业发展转型的驱动力&#xff0c;也是开发者最棘手的问题。前日&#xff0c;MongoDB携手阿里云、NineData在杭州成功举办了“数据驱动&#xff0c;敏捷前行——MongoDB企业开发加速器”技术沙龙。此次活动吸引了来自各行各业的专业人员&#xff0c;共同探讨MongoDB的…

vscode c++可以找到声明却无法自动补全

这个问题折磨了我将近一个月&#xff0c;今天终于被解决了&#xff0c;特此记录 情景再现 事情的起因是我在学习华为的Ascend C算子&#xff0c;需要编写C代码。关于怎么下载库文件怎么编译之类的不是本文的重点&#xff0c;重点是自动补全。 我已经拿到库文件了&#xff0c…

Git命令常规操作

目录 常用操作示意图 文件的状态变化周期 1. 创建文件 2. 修改原有文件 3. 删除原有文件 没有添加到暂存区的数据直接 rm 删除即可&#xff1a; 对于添加到暂存区的数据 文件或目录&#xff1a; 4. 重命名暂存区数据 5. 查看历史记录 6. 还原历史数据 恢复过程的原…