【SGX系列教程】(三)Intel-SGX 官方示例分析(SampleCode)——Cxx11SGXDemo

文章目录

  • 示例一. Cxx11SGXDemo
    • 1.1 README
    • 1.2 重点代码分析
      • 1.2.1 App/App.cpp
      • 1.2.2 App/TrustedLibrary/Libcxx.cpp
      • 1.2.3 Enclave.edl
      • 1.2.4 Enclave/TrustedLibrary/Libcxx.cpp
      • 1.2.5 Enclave/Enclave.cpp+Enclave.h
    • 1.3 编译执行
    • 1.4 总结
  • 示例二. Cxx14SGXDemo
  • 示例三. Cxx17SGXDemo
  • 四. 参考链接
  • 五. 感谢支持

    下面将给出一些sgx源码包中的示例分析,从中学习SGX的基本使用方法:
关于 SGX 开发运行环境的搭建可参考之前的一篇博客:【SGX系列教程】(一)。

示例一. Cxx11SGXDemo

1.1 README

-----------------------
Purpose of Cxx11SGXDemo
-----------------------
The project demonstrates serveral C++11 features inside the Enclave:
- lambda expressions;
- rvalue references and move semantics;
- automatic type deduction with auto and decltype;
- nullptr type;
- strongly typed enum classes;
- Range-based for statements;
- static_assert keyword for compile-time assertion;
- initializer lists and uniform initialization syntax;
- New virtual function controls: override, final, default, and delete;
- delegating constructors;
- new container classes (unordered_set, unordered_map, unordered_multiset, and unordered_multimap);
- tuple class;
- function object wrapper;
- atomic, mutexes, condition_variables;
- new smart pointer classes: shared_ptr, unique_ptr;
- new c++ algorithms: all_of, any_of, none_of;
- variadic templates;
- SFINAE;

---------------------------------------------
How to Build/Execute the C++11 sample program
---------------------------------------------
1. Install Intel(R) Software Guard Extensions (Intel(R) SGX) SDK for Linux* OS
2. Enclave test key(two options):
    a. Install openssl first, then the project will generate a test key<Enclave_private_test.pem> automatically when you build the project.
    b. Rename your test key(3072-bit RSA private key) to <Enclave_private_test.pem> and put it under the <Enclave> folder.
3. Make sure your environment is set:
    $ source ${sgx-sdk-install-path}/environment
4. Build the project with the prepared Makefile:
    a. Hardware Mode, Debug build:
        $ make
    b. Hardware Mode, Pre-release build:
        $ make SGX_PRERELEASE=1 SGX_DEBUG=0
    c. Hardware Mode, Release build:
        $ make SGX_DEBUG=0
    d. Simulation Mode, Debug build:
        $ make SGX_MODE=SIM
    e. Simulation Mode, Pre-release build:
        $ make SGX_MODE=SIM SGX_PRERELEASE=1 SGX_DEBUG=0
    f. Simulation Mode, Release build:
        $ make SGX_MODE=SIM SGX_DEBUG=0
5. Execute the binary directly:
    $ ./app
6. Remember to "make clean" before switching build mode

-------------------------------------------------
Launch token initialization
-------------------------------------------------
If using libsgx-enclave-common or sgxpsw under version 2.4, an initialized variable launch_token needs to be passed as the 3rd parameter of API sgx_create_enclave. For example,

sgx_launch_token_t launch_token = {0};
sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, launch_token, NULL, &global_eid, NULL);

    工程的主要功能是测试c++11的一些特性在enclave中的执行情况,根据上面README中的内容总结一下Cxx11SGXDemo的执行步骤如下:

  1. 首先需要安装SGX sdk,以及等等对SGX的支持测试,具体可参考之前的一篇博客:【SGX系列教程】(一);
  2. 安装openssl,目的是为enclave.so生成签名私钥:

openssl genrsa -out Enclave/Enclave_private_test.pem -3 3072

  1. 确保sdk路径生效(source),基本在安装sdk时会指定安装路径为:/opt/intel/sgxsdk
  2. 使用Makefile构建工程:
    • 硬件模式, Debug build:
      make
    • 硬件模式, Pre-release build:
      make SGX_PRERELEASE=1 SGX_DEBUG=0
    • 硬件模式, Release build:
      make SGX_DEBUG=0
    • 仿真模式, Debug build:
      make SGX_MODE=SIM
    • 仿真模式, Pre-release build:
      make SGX_MODE=SIM SGX_PRERELEASE=1 SGX_DEBUG=0
    • 仿真模式, Release build:
      make SGX_MODE=SIM SGX_DEBUG=0
  3. 执行:./app
  4. 在切换编译模式之前记得make clean

1.2 重点代码分析

    SGX工程的整个构建流程在上一篇文章中已经给出给出了详细教程:【SGX系列教程】(二)第一个 SGX 程序: HelloWorld,因此在此处仅给出部分重点代码分析,主要讲清楚enclave如何支持c++11的运行,并提供哪些支持,其他通用代码不做展开分析。

    文件目录如下图,主要关注图中框出来的两个文件,其中Enclave文件夹中的Libxx.cpp提供enclave中函数执行功能,是系统的核心功能文件(将在后面详细分析文件功能),并封装成ECALL函数由外部调用;而App文件夹中的Libxx.cpp负责调用上述的ECALL函数
在这里插入图片描述
    整个程序调用过程可先总结为下图:
在这里插入图片描述

1.2.1 App/App.cpp

#include <stdio.h>      // 标准输入输出库,提供如 printf 等函数
#include <string.h>     // 字符串处理函数库
#include <assert.h>     // 断言函数库,用于调试

# include <unistd.h>    // 提供对 POSIX 操作系统 API 的访问,包括文件和进程
# include <pwd.h>       // 提供对用户密码信息的访问
# define MAX_PATH FILENAME_MAX // 定义 MAX_PATH 为系统最大文件名长度

#include "sgx_urts.h"   // SGX 用户运行时库,提供 SGX 相关 API
#include "App.h"        // 应用程序相关的头文件
#include "Enclave_u.h"  // Untrusted Enclave 的接口头文件

/* 全局 EID 由多个线程共享 */
sgx_enclave_id_t global_eid = 0;  // 定义一个全局的 SGX enclave ID

/* 错误代码结构体 */
typedef struct _sgx_errlist_t {
    sgx_status_t err;    // 错误码
    const char *msg;     // 错误信息
    const char *sug;     // 错误建议
} sgx_errlist_t;

/* 由 sgx_create_enclave 返回的错误代码 */
static sgx_errlist_t sgx_errlist[] = {  // 错误列表,包含常见的 SGX 错误码及其信息
    {
        SGX_ERROR_UNEXPECTED,
        "Unexpected error occurred.",
        NULL
    },
    {
        SGX_ERROR_INVALID_PARAMETER,
        "Invalid parameter.",
        NULL
    },
    {
        SGX_ERROR_OUT_OF_MEMORY,
        "Out of memory.",
        NULL
    },
    {
        SGX_ERROR_ENCLAVE_LOST,
        "Power transition occurred.",
        "Please refer to the sample \"PowerTransition\" for details."
    },
    {
        SGX_ERROR_INVALID_ENCLAVE,
        "Invalid enclave image.",
        NULL
    },
    {
        SGX_ERROR_INVALID_ENCLAVE_ID,
        "Invalid enclave identification.",
        NULL
    },
    {
        SGX_ERROR_INVALID_SIGNATURE,
        "Invalid enclave signature.",
        NULL
    },
    {
        SGX_ERROR_OUT_OF_EPC,
        "Out of EPC memory.",
        NULL
    },
    {
        SGX_ERROR_NO_DEVICE,
        "Invalid SGX device.",
        "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards."
    },
    {
        SGX_ERROR_MEMORY_MAP_CONFLICT,
        "Memory map conflicted.",
        NULL
    },
    {
        SGX_ERROR_INVALID_METADATA,
        "Invalid enclave metadata.",
        NULL
    },
    {
        SGX_ERROR_DEVICE_BUSY,
        "SGX device was busy.",
        NULL
    },
    {
        SGX_ERROR_INVALID_VERSION,
        "Enclave version was invalid.",
        NULL
    },
    {
        SGX_ERROR_INVALID_ATTRIBUTE,
        "Enclave was not authorized.",
        NULL
    },
    {
        SGX_ERROR_ENCLAVE_FILE_ACCESS,
        "Can't open enclave file.",
        NULL
    },
    {
        SGX_ERROR_NDEBUG_ENCLAVE,
        "The enclave is signed as product enclave, and can not be created as debuggable enclave.",
        NULL
    },
    {
        SGX_ERROR_MEMORY_MAP_FAILURE,
        "Failed to reserve memory for the enclave.",
        NULL
    },
};

/* 打印错误信息 */
void print_error_message(sgx_status_t ret)
{
    size_t idx = 0;  // 循环索引
    size_t ttl = sizeof sgx_errlist / sizeof sgx_errlist[0];  // 错误列表的总长度
    // 遍历错误列表,查找对应的错误
    for (idx = 0; idx < ttl; idx++) {
        if (ret == sgx_errlist[idx].err) {  // 找到对应的错误码
            if (NULL != sgx_errlist[idx].sug)  // 如果存在建议,打印建议
                printf("Info: %s\n", sgx_errlist[idx].sug);
            printf("Error: %s\n", sgx_errlist[idx].msg);  // 打印错误信息
            break;
        }
    }
    if (idx == ttl)  // 如果遍历后未找到相应错误码,打印未预期的错误发生
        printf("Error: Unexpected error occurred.\n");
}

/* 初始化信任域:
 * 调用 sgx_create_enclave 来初始化一个信任域实例
 */
int initialize_enclave(void)
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;  // 初始化错误状态
    /* 调用 sgx_create_enclave 来初始化一个信任域实例 */
    /* 调试支持:将第二个参数设置为 1 */   
    ret = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);
    if (ret != SGX_SUCCESS) {  // 如果初始化失败,打印错误信息
        print_error_message(ret);
        return -1;  // 返回错误状态
    }
    return 0;  // 成功初始化,返回0
}

/* OCall 函数,由enclave.cpp中函数调用:ocall_print_string(buf) */
void ocall_print_string(const char *str)
{
    printf("%s", str);
}

/* 主应用程序main入口 */
int SGX_CDECL main(int argc, char *argv[])
{
    (void)(argc);  // 防止未使用参数警告
    (void)(argv);   
    /* 初始化信任域 */
    if (initialize_enclave() < 0) {  // 如果信任域初始化失败,打印信息并退出
        printf("Enter a character before exit ...\n");
        getchar();  // 等待用户输入
        return -1;  
    }
    /* 使用信任库函数,定义在App/TrustedLibrary/Libcxx.cpp文件中*/
    ecall_libcxx_functions();  // 调用 ECALL 函数,利用受信任的 C++11库
    /* 销毁信任域 */
    sgx_destroy_enclave(global_eid);  // 销毁信任域实例

    printf("Info: Cxx11DemoEnclave successfully returned.\n");  
    // 打印成功信息
    //printf("Enter a character before exit ...\n");
    //getchar();  // 此行代码被注释掉,仅供调试时使用
    return 0;  // 返回0,表示程序正常退出
}

    上述实现了一个简单的SGX应用程序,主要功能包括:初始化SGX信任域、调用受信任代码、打印错误信息和与主机间通信。用于展示如何在C++中利用Intel SGX进行安全函数的调用和管理。可以看出函数ecall_libcxx_functions()是核心功能函数。下面介绍该函数。

1.2.2 App/TrustedLibrary/Libcxx.cpp

#include <stdio.h>
#include "../App.h"
#include "Enclave_u.h"
#include <thread>

// 该函数调用了标准的C++11功能。
// 这个函数是互斥锁演示的一部分
void demo_counter_without_mutex()
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用不使用保护的互斥锁计数演示
    ret = ecall_mutex_demo_no_protection(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 这个函数是互斥锁演示的一部分
void demo_counter_mutex()
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用使用保护的互斥锁计数演示
    ret = ecall_mutex_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 这个函数是条件变量演示的处理线程使用
void demo_cond_var_run()
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用条件变量运行演示
    ret = ecall_condition_variable_run(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 这个函数是条件变量演示的加载线程使用
void demo_cond_var_load()
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // ecall调用条件变量加载演示
    ret = ecall_condition_variable_load(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
}

// 示例展示了C++11库和编译器特性,被App.cpp中main函数调用
void ecall_libcxx_functions(void)
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;
    // lambda函数特性的示例
    ret = ecall_lambdas_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // auto特性的示例
    ret = ecall_auto_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // decltype特性的示例
    ret = ecall_decltype_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 强类型枚举特性的示例
    ret = ecall_strongly_typed_enum_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 基于范围的for循环特性的示例
    ret = ecall_range_based_for_loops_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 静态断言特性的示例
    ret = ecall_static_assert_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 虚函数控制特性的示例:override, final, default, and delete
    ret = ecall_virtual_function_control_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 委派构造函数特性的示例
    ret = ecall_delegating_constructors_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // std::function特性的示例
    ret = ecall_std_function_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 算法特性的示例(std::all_of, std::any_of, std::none_of)
    ret = ecall_cxx11_algorithms_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 可变参数模板特性的示例
    ret = ecall_variadic_templates_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // SFINAE特性的示例
    ret = ecall_SFINAE_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 初始化列表特性的示例
    ret = ecall_initializer_list_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 右值引用特性的示例
    ret = ecall_rvalue_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // nullptr特性的示例
    ret = ecall_nullptr_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 枚举类特性的示例
    ret = ecall_enum_class_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 新容器类特性的示例(unordered_set, unordered_map, unordered_multiset, 和 unordered_multimap)
    ret = ecall_new_container_classes_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 元组特性的示例
    ret = ecall_tuple_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // shared_ptr特性的示例
    ret = ecall_shared_ptr_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 原子操作特性的示例
    ret = ecall_atomic_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 以下线程是互斥锁演示的一部分
    std::thread t1(demo_counter_without_mutex);
    std::thread t2(demo_counter_without_mutex);
    std::thread t3(demo_counter_without_mutex);
    t1.join();
    t2.join();
    t3.join();
    ret = ecall_print_final_value_no_protection(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 以下线程是互斥锁演示的一部分
    std::thread tm1(demo_counter_mutex);
    std::thread tm2(demo_counter_mutex);
    std::thread tm3(demo_counter_mutex);
    tm1.join();
    tm2.join();
    tm3.join();
    ret = ecall_print_final_value_mutex_demo(global_eid);
    if (ret != SGX_SUCCESS)
        abort();  // 如果调用失败,程序终止
    // 以下线程是条件变量演示的一部分
    std::thread th1(demo_cond_var_run);
    std::thread th2(demo_cond_var_load);
    th2.join();
    th1.join();
}
  • ecall_libcxx_functions 函数:该函数展示了C++11的新特性和库功能。包括lambda表达式、auto、decltype、强类型枚举、基于范围的for循环、静态断言、虚函数控制、委派构造函数、std::function、算法、可变参数模板、SFINAE、初始化列表、右值引用、nullptr、枚举类、新容器类、元组、shared_ptr和原子操作等。函数通过调用一系列封装在Enclave中的示例函数,展示了这些特性。
  • demo_counter_without_mutexdemo_counter_mutex 函数:演示了使用和不使用互斥锁进行计数的区别。
  • demo_cond_var_rundemo_cond_var_load 函数:演示了条件变量的使用。

    上述ecall开头的函数主要通过edl文件中定义的接口调用Enclave/TrustedLibrary/Libcxx.cpp中的函数。下面介绍Enclave.edl文件内容。

1.2.3 Enclave.edl

    Enclave.edl原始文件内容如下:

/* Enclave.edl - Top EDL file. */
enclave {
    
    /* Import ECALL/OCALL from sub-directory EDLs.
     *  [from]: specifies the location of EDL file. 
     *  [import]: specifies the functions to import, 
     *  [*]: implies to import all functions.
     */
    from "TrustedLibrary/Libcxx.edl" import *;
    from "sgx_tstdc.edl" import *;

    /* 
     * ocall_print_string - invokes OCALL to display string buffer inside the enclave.
     *  [in]: copy the string buffer to App outside.
     *  [string]: specifies 'str' is a NULL terminated buffer.
     */
    untrusted {
        void ocall_print_string([in, string] const char *str);
    };
};

   可以看出,上面的原文件中只定义了untrusted部分的函数接口。而对于trusted部分的函数接口则是通过从sub-directory EDLs Import的方式导入的,类似于c语言的Include的头文件导入。将导入放进来之后,最终形成的完整的 Enclave.edl文件内容如下:

/* Enclave.edl - Top EDL file. */
enclave {
    trusted {
		public void ecall_lambdas_demo(void);
		public void ecall_auto_demo(void);
		public void ecall_decltype_demo(void);
		public void ecall_strongly_typed_enum_demo(void);
		public void ecall_range_based_for_loops_demo(void);
		public void ecall_static_assert_demo(void);
		public void ecall_virtual_function_control_demo(void);
		public void ecall_delegating_constructors_demo(void);
		public void ecall_std_function_demo(void);
		public void ecall_cxx11_algorithms_demo(void);
		public void ecall_variadic_templates_demo(void);
		public void ecall_SFINAE_demo(void);
		public void ecall_initializer_list_demo(void);
		public void ecall_rvalue_demo(void);
		public void ecall_nullptr_demo(void);
        public void ecall_enum_class_demo(void);
		public void ecall_new_container_classes_demo(void);
		public void ecall_tuple_demo(void);
		public void ecall_shared_ptr_demo(void);
		public void ecall_atomic_demo(void);
		public void ecall_mutex_demo(void);
		public void ecall_print_final_value_mutex_demo(void);
		public void ecall_mutex_demo_no_protection(void);
		public void ecall_print_final_value_no_protection(void);
		public void ecall_condition_variable_run(void);
		public void ecall_condition_variable_load(void);
    };

    /* 
     * ocall_print_string - invokes OCALL to display string buffer inside the enclave.
     *  [in]: copy the string buffer to App outside.
     *  [string]: specifies 'str' is a NULL terminated buffer.
     */
    untrusted {
        void ocall_print_string([in, string] const char *str);
    };
};

   edl中定义的这些函数接口规定了REE和TEE之间交互的函数接口,trusted中定义的这些函数就是上面在App/TrustedLibrary/Libcxx.cpp中调用的那些函数。而ocall_print_string([in, string] const char *str)就是enclave主动调用的外部接口,将在Enclave/Enclave.cpp调用。下面给出这些ecall函数的实现源码,在Enclave/TrustedLibrary/Libcxx.cpp路径文件中。

1.2.4 Enclave/TrustedLibrary/Libcxx.cpp

#include <string>
#include <vector>
#include <iterator>
#include <typeinfo>
#include <functional>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <initializer_list>
#include <tuple>
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <map>
#include "../Enclave.h" // 引入上层 Enclave 相关的头文件
#include "Enclave_t.h"  // 引入自动生成的 Enclave受信部分的头文件

// Feature name        : Lambda functions
// Feature description : 用于创建可以捕获作用域中变量的函数对象
// Demo description    : 显示 lambda 捕获选项和一些基本用法
void ecall_lambdas_demo()
{
    // Lambdas 捕获选项:
    int local_var = 0;
    [] { return true; };                     // 不捕获任何变量
    [&] { return ++local_var; };             // 通过引用捕获所有变量
    [&local_var] { return ++local_var; };    // 通过引用捕获 local_var
    [&, local_var] { return local_var; };    // 通过引用捕获所有变量,local_var 通过值捕获

    [=] { return local_var; };               // 通过值捕获所有变量
    [local_var] { return local_var; };       // 通过值捕获 local_var
    [=, &local_var] { return ++local_var; }; // 通过值捕获所有变量,local_var 通过引用捕获

    // 使用 Lambdas 的示例:
    std::vector<int> v { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    printf("[Lambdas] 初始数组使用 lambdas: { ");
    // 使用 Lambdas 打印数组中的元素
    std::for_each(std::begin(v), std::end(v), [](int elem) { printf("%d ", elem); }); // 捕获规范
    printf("}.\n");
    // 使用 Lambda 作为一元谓词调用 find_if,找到第一个奇数
    auto first_odd_element = std::find_if(std::begin(v), std::end(v), [=](int elem) { return elem % 2 == 1; });

    if (first_odd_element != std::end(v))
        printf("[Lambdas] 数组中的第一个奇数是 %d. \n", *first_odd_element);
    else
        printf("[Lambdas] 在数组中未找到奇数。\n");
    // 使用 Lambda 作为一元谓词调用 count_if,计算偶数的数量
    long long number_of_even_elements = std::count_if(std::begin(v), std::end(v), [=](int val) { return val % 2 == 0; });
    printf("[Lambdas] 数组中的偶数数量是 %lld.\n", number_of_even_elements);
    // 使用 Lambdas 对数组元素进行排序
    std::sort(std::begin(v), std::end(v), [](int e1, int e2) { return e2 < e1; });
    // 使用 Lambdas 打印排序后的数组元素
    printf("[Lambdas] 排序后的数组: { ");
    std::for_each(std::begin(v), std::end(v), [](int elem) { printf("%d ", elem); });
    printf("}. \n");
    printf("\n"); // 演示结束
}

// ecall_auto_demo 的辅助函数:
void sample_func_auto_demo()
{
    printf("[auto] 调用函数 sample_func_auto_demo.\n");
}
// Feature name        : auto
// Feature description : 用于自动类型推导
// Demo description    : 显示 auto 关键字在不同类型下的基本用法
void ecall_auto_demo()
{
    double local_var = 0.0;
    auto a = 7; // 自动推导变量 a 的类型为 int
    printf("[auto] a 的类型是 int. typeid = %s.\n", typeid(a).name());
    const auto b1 = local_var, *b2 = &local_var; // auto 可以与 const 或 & 一起使用
    printf("[auto] b1 的类型是 const double. typeid = %s.\n", typeid(b1).name());
    printf("[auto] b2 的类型是 const double*. typeid = %s.\n", typeid(b2).name());
    (void)b1;
    (void)b2;

    auto c = 0, *d = &a; // 当推导类型相同时可以初始化多个变量
    printf("[auto] c 的类型是 int. typeid = %s.\n", typeid(c).name());
    printf("[auto] d 的类型是 int*. typeid = %s.\n", typeid(d).name());
    (void)c;
    (void)d;

    auto lambda = [] {}; // 可以用来定义 lambdas
    printf("[auto] lambda 的类型是 [] {}. typeid = %s.\n", typeid(lambda).name());
    (void)lambda;

    auto func = sample_func_auto_demo; // 可以用来推导函数类型
    printf("[auto] func 的类型是 void(__cdecl*)(void). typeid = %s.\n", typeid(func).name());
    func();
    printf("\n"); // 演示结束
}

// Feature name        : decltype
// Feature description : 用于类型推导
// Demo description    : 显示 decltype 关键字在不同类型下的基本用法
void ecall_decltype_demo()
{
    int a = 0 ;
    decltype(a) b = 0; // 声明同类型变量 b
    printf("[decltype] b 的类型是 int. typeid = %s.\n", typeid(b).name());
    double c = 0;
    decltype(a + c) sum = a + c; // 推导不同类型变量相加的结果类型
                                 // 在模板中很常用
    printf("[decltype] sum 的类型是 double. typeid = %s.\n", typeid(sum).name());
    (void)sum;
    (void)b;
    printf("\n"); // 演示结束
}

// Feature name         : enum classes
// Feature description  : 新的枚举类型,解决旧枚举类型中的问题:
//                        枚举值的范围未限定以及与 int 类型的比较可能性
// Demo description     : 显示 enum classes 的基本用法
void ecall_strongly_typed_enum_demo()
{
    // 在 enum class 中可以设定底层类型。这里设定为 char。
    enum class DaysOfWeek : char { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };
    // 初始化 DaysOfWeek 类型的变量
    DaysOfWeek random_day = DaysOfWeek::MONDAY;
    (void)random_day;
    // 不强制规定底层类型
    enum class Weekend { SATURDAY, SUNDAY };
}

// Feature name        : Range based for loops
// Feature description : 方便读取容器中的元素
// Demo description    : 显示在 C 数组和 vector 中的基本用法
void ecall_range_based_for_loops_demo()
{
    char array_of_letters[] = { 'a', 'b', 'c', 'd' };
    std::vector<char> vector_of_letters = { 'a', 'b', 'c', 'd' };
    printf("[range_based_for_loops] 使用 range based for loop 打印数组内容: { ");
    for (auto elem : array_of_letters)
        printf("%c ", elem);
    printf("}. \n");
    printf("[range_based_for_loops] 使用 range based for loop 打印 vector 内容: { ");
    for (auto elem : vector_of_letters)
        printf("%c ", elem);
    printf("}.\n");
    printf("\n"); // 演示结束
}

// Feature name        : static_assert
// Feature description : 用于编译时断言
// Demo description    : 显示 static_assert 在编译时操作中的基本用法
void ecall_static_assert_demo()
{
    static_assert(sizeof(int) < sizeof(double), "错误:sizeof(int) < sizeof(double)");
    const int a = 0;
    static_assert(a == 0, "错误:a 的值不为 0");
}

// Feature name        : New virtual function controls : override, final, default, and delete
// Feature description : - delete   : 删除的函数不能被继承
//                       - final    : 使用 final 修饰的函数不能被子类重写
//                       - default  : 告知编译器生成一个默认函数
//                       - override : 确保派生类中的虚函数重写基类中的函数
// Demo description : 显示新虚函数控制的基本用法
/* ecall_virtual_function_control_demo 的辅助类 */
class Base
{
public:
    virtual void f_cannot_be_inherited() final {}; // 使用 final 修饰,不能被继承的方法
    Base(const Base &) = delete;                   // 删除拷贝构造函数,不允许拷贝
    Base() = default;                              // 默认构造函数
    virtual void f_must_be_overridden() {};        // 需要在派生类中重写的方法
    virtual ~Base() {};                            // 虚析构函数,保证派生类对象的正确析构
};

/* ecall_virtual_function_control_demo 的辅助类 */
class Derived : Base
{
public:
    /* 注释中的代码无法编译
     * 由于基类中的方法使用了 final 关键字,所以子类不能重写这个方法
     * virtual double f_cannot_be_inherited() {};
     */
    /* 关键字 override 确保此函数重写了基类成员函数 */
    virtual void f_must_be_overridden() override {};
};

void ecall_virtual_function_control_demo()
{
    // 使用默认构造函数生成对象
    Base a;
    // 尝试使用拷贝构造函数,此处代码会因该函数被删除而无法编译
    // Base b = a;
}

// Feature name        : Delegating constructors
// Feature description : 类的构造函数可能具有相同的代码,可以委托给另一个构造函数以避免代码重复
// Demo description    : 显示委托构造函数的基本使用方法
// ecall_delegating_constructors_demo 的辅助类
class DemoDelegatingConstructors
{
    int a, b, c;
public:
    DemoDelegatingConstructors(int param_a, int param_b, int param_c)
    {
        this->a = param_a;
        this->b = param_b;
        this->c = param_c;
        /* 公共初始化 */
        switch (c)
        {
        case 1:
            printf("[delegating constructors] 调用自 DemoDelegatingConstructors(int a, int b).\n");
            break;
        case 2:
            printf("[delegating constructors] 调用自 DemoDelegatingConstructors(int a).\n");
            break;
        default:
            printf("[delegating constructors] 调用自 DemoDelegatingConstructors(int a, int b, int c).\n");
            break;
        }
    }
    DemoDelegatingConstructors(int param_a, int param_b) : DemoDelegatingConstructors(param_a, param_b, 1) {}
    DemoDelegatingConstructors(int param_a) : DemoDelegatingConstructors(param_a, 0, 2) {}
};

void ecall_delegating_constructors_demo()
{
    DemoDelegatingConstructors a(1, 2, 3);
    DemoDelegatingConstructors b(1, 2);
    DemoDelegatingConstructors c(1);
   
    printf("\n"); // 演示结束
}

void sample_std_function1()  // ecall_std_function_demo 的辅助函数
{
    printf("[std_function] 调用 sample_std_function1\n");
}
// Feature name        : std::function
// Feature description : 用于存储和调用可调用对象
// Demo description    : 显示 std::function 的基本使用方法
void ecall_std_function_demo()
{
    // 函数示例
    std::function<void()> funct = sample_std_function1;
    funct();
    // Lambda 示例
    std::function<void()> funct_lambda = [] { printf("[std_function] 调用一个 lambda 函数\n");  };
    funct_lambda();
    printf("\n"); // 演示结束
}

// Feature name        : std::all_of, std::any_of, std::none_of
// Feature description : 新的 C++11 算法
// Demo description    : 显示 std::all_of, std::any_of 和 std::none_of 的基本使用方法
void ecall_cxx11_algorithms_demo()
{
    std::vector<int> v = { 0, 1, 2, 3, 4, 5 };
    bool are_all_of = all_of(begin(v), end(v), [](int e) { return e % 2 == 0; });
    printf("[cxx11_algorithms] 所有元素在 { 0 1 2  3 4 5 } 中都是偶数是 %s.\n", are_all_of ? "true" : "false");
    bool are_any_of = any_of(begin(v), end(v), [](int e) { return e % 2 == 0; });
    printf("[cxx11_algorithms] { 0 1 2 3 4 5 } 中的一些元素为偶数是 %s.\n", are_any_of ? "true" : "false");
    bool are_none_of = none_of(begin(v), end(v), [](int e) { return e % 2 == 0; });
    printf("[cxx11_algorithms] { 0 1 2 3 4 5 } 中无元素为偶数是 %s.\n", are_none_of ? "true" : "false");
    printf("\n"); // 演示结束
}

template<typename T>  // ecall_variadic_templates_demo 的辅助模板
T sum(T elem)
{
    return elem;
}
// Feature name        : variadic templates
// Feature description : 可以有多个参数的模板
// Demo description    : 显示变参模板的基本使用方法
template<typename T, typename... Args>
T sum(T elem1, T elem2, Args... args)
{
    return elem1 + elem2 + sum(args...);
}
void ecall_variadic_templates_demo()
{
    int computed_sum = sum(1, 2, 3, 4, 5);
    printf("[variadic_templates] 参数 (1, 2, 3, 4, 5) 的和是 %d.\n", computed_sum);
    printf("\n"); // 演示结束
}

// Feature name        : Substitution failure is not an error (SFINAE)
// Feature description : 说明模板中替换错误不导致错误的情况
// Demo description    : 显示 SFINAE 的基本使用方法
/*第一个替换候选者*/
template <typename T> void f(typename T::A*) { printf("[sfinae] 第一个替换候选者匹配.\n"); };
/*第二个替换候选者*/
template <typename T> void f(T) { printf("[sfinae] 第二个替换候选者匹配.\n"); }
void ecall_SFINAE_demo()
{
    f<int>(0x0);   // 尽管第一个候选者替换失败,第二个候选者仍然匹配
    printf("\n");  // 演示结束
}

// Feature name        : Initializer lists
// Feature description : 一个 std::initializer_list<T> 类型的对象是一个轻量级代理对象,提供对 const T 类型对象数组的访问
// Demo description    : 演示在构造函数中使用初始化列表的用法
class Number
{
public:
    Number(const std::initializer_list<int> &v) {
        for (auto i : v) {
            elements.push_back(i);
        }
    }
    void print_elements() {
        printf("[initializer_list] 向量中的元素是:");
        for (auto item : elements) {
            printf(" %d", item);
        }
        printf(".\n");
    }
private:
    std::vector<int> elements;
};
void ecall_initializer_list_demo()
{
    printf("[initializer_list] 在构造函数中使用初始化列表.\n");
    Number m = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
    m.print_elements();
    printf("\n"); //演示结束
}


// ecall_rvalue_demo 的辅助类
class DemoBuffer
{
public:
    unsigned int size = 100;
    char *buffer;
    DemoBuffer(int param_size)
    {
        this->size = param_size;
        buffer = new char[size];
        printf("[rvalue] 调用构造函数 : DemoBuffer(int size).\n");
    }
    // 传统拷贝构造函数需要为新副本分配内存
    // 拷贝一个大数组是一个耗时操作
    DemoBuffer(const DemoBuffer &rhs)
    {
        this->size = rhs.size;
        buffer = new char[rhs.size];
        memcpy(buffer, rhs.buffer, size);
        printf("[rvalue] 调用拷贝构造函数 : DemoBuffer(const DemoBuffer &rhs).\n");
    }
    // 典型的移动构造函数可以重用 buffer 指向的内存
    DemoBuffer(DemoBuffer &&rhs)
    {
        buffer = rhs.buffer;
        size = rhs.size;
        // 重置 rhs 的状态
        rhs.buffer = NULL;
                rhs.size = 0;
        printf("[rvalue] 调用移动构造函数 : DemoBuffer(DemoBuffer && rhs).\n");
    }
    ~DemoBuffer()
    {
        delete [] buffer;
    }
};
// ecall_rvalue_demo 的辅助函数
DemoBuffer foobar(int a)
{
    DemoBuffer x(100);
    DemoBuffer y(100);
    if (a > 0)
        return x;
    else
        return y;
}
// Feature name        : Rvalue references and move semantics;
// Feature description : 通过消除复制操作来优化内存使用
// Demo description    : 显示右值引用、移动构造函数和移动赋值运算符的基本使用方法
void ecall_rvalue_demo()
{
    // 这将调用构造函数
    printf("[rvalue] DemoBuffer a(100).\n");
    DemoBuffer a(100);
    printf("[rvalue] 调用 foobar(100). \n");
    // 使用临时对象初始化变量 d ,将调用移动构造函数
    // 这有助于减少操作的内存开销
    DemoBuffer d(foobar(100));
    // 这将调用拷贝构造函数。a 的状态不会改变
    printf("[rvalue] DemoBuffer b(a).\n");
    DemoBuffer b(a);
    printf("[rvalue] DemoBuffer c(std::move(a)).\n");
    // 显式将 a 转换为右值,以便 c 使用移动构造函数进行创建
    // a 的状态将被重置
    DemoBuffer c(std::move(a));
    printf("\n"); // 演示结束
}

// Feature name        : Nullptr
// Feature description : 解决将 NULL 转换为整型的问题
// Demo description    : 显示 nullptr 的基本使用方法
// 重载候选 1
void nullptr_overload_candidate(int i) {
    (void)i;
    printf("[nullptr] 调用了 void nullptr_overload_candidate(int i).\n");
}
// 重载候选 2
void nullptr_overload_candidate(int* ptr) {
    (void)ptr;
    printf("[nullptr] 调用了 void nullptr_overload_candidate(int* ptr).\n");
}

template<class F, class A>
void Fwd(F f, A a)
{
    f(a);
}
void g(int* i)
{
    (void)i;
    printf("[nullptr] 调用了函数 %s\n", __FUNCTION__);
}
void ecall_nullptr_demo()
{
    // NULL 可以转换为整型(如 int),将调用重载候选 1
    nullptr_overload_candidate(NULL);
    // nullptr 不能转换为整型(如 int),将调用重载候选 2
    nullptr_overload_candidate(nullptr);
    g(NULL);           // 合法
    g(0);              // 合法
    Fwd(g, nullptr);   // 合法
    //Fwd(g, NULL);  // 错误:没有函数 g(int)
    printf("\n"); // 演示结束
}

// Feature name        : Scoped enums
// Feature description : 新的枚举类型,解决旧枚举类型中的问题
// Demo description    : 显示 scoped enums 的基本使用方法
enum class Color { orange, brown, green = 30, blue, red };
void ecall_enum_class_demo()
{
    int n = 0;
    Color color1 = Color::brown;
    switch (color1)
    {
        case Color::orange: printf("[enum class] orange"); break;
        case Color::brown:  printf("[enum class] brown"); break;
        case Color::green:  printf("[enum class] green"); break;
        case Color::blue:   printf("[enum class] blue"); break;
        case Color::red:    printf("[enum class] red"); break;
    }
    // n = color1; // 不允许:没有 scoped enum 到 int 的转换
    n = static_cast<int>(color1); // 合法,n = static_cast<int>(Color::brown) = 1
    printf(" - int = %d\n", n);

    Color color2 = Color::red;
    switch (color2)
    {
        case Color::orange: printf("[enum class] orange"); break;
        case Color::brown:  printf("[enum class] brown"); break;
        case Color::green:  printf("[enum class] green"); break;
        case Color::blue:   printf("[enum class] blue"); break;
        case Color::red:    printf("[enum class] red"); break;
    }
    n = static_cast<int>(color2); // 合法,n = static_cast<int>(Color::red) = 32
    printf(" - int = %d\n", n);
    Color color3 = Color::green;
    switch (color3)
    {
        case Color::orange: printf("[enum class] orange"); break;
        case Color::brown:  printf("[enum class] brown"); break;
        case Color::green:  printf("[enum class] green"); break;
        case Color::blue:   printf("[enum class] blue"); break;
        case Color::red:    printf("[enum class] red"); break;
    }
    n = static_cast<int>(color3); // 合法,n = static_cast<int>(Color::green) = 30
    printf(" - int = %d\n", n);
    printf("\n");
}

// Feature name        : new container classes
// Feature description : unordered_set, unordered_map, unordered_multiset 和 unordered_multimap
// Demo description    : 显示新容器类的基本使用方法
void ecall_new_container_classes_demo()
{
    // unordered_set
    // 一个基于哈希表的无序集合,提供快速查找功能
    std::unordered_set<int> set_of_numbers = { 0, 1, 2, 3, 4, 5 };
    const int searchVal = 3;
    std::unordered_set<int>::const_iterator got = set_of_numbers.find(searchVal);
    if (got != set_of_numbers.end())
        printf("[new_container_classes] unordered_set { 0, 1, 2, 3, 4, 5} 包含值 %d.\n", searchVal);
    else
        printf("[new_container_classes] unordered_set { 0, 1, 2, 3, 4, 5} 不包含值 %d.\n", searchVal);
    // unordered_multiset
    // 一个基于哈希表的无序多重集合,可以包含重复元素
    std::unordered_multiset<int> multiset_of_numbers = { 0, 1, 2, 3, 3, 3 };
    printf("[new_container_classes] unordered_multiset { 0, 1, 2, 3, 3, 3} 包含 %d 个值 %d.\n",
        (int)multiset_of_numbers.count(searchVal), searchVal);
    // unordered_map
    std::unordered_map<std::string, int> grades{ { "A", 10 },{ "B", 8 },{ "C", 7 },{ "D", 5 },{ "E", 3 } };
    printf("[new_container_classes] unordered_map 元素: {");
    for (auto pair : grades) {
        printf("[%s %d] ", pair.first.c_str(), pair.second);
    }
    printf("}.\n");
    // unordered_multimap
    std::unordered_multimap<std::string, int> multimap_grades{ { "A", 10 },{ "B", 8 },{ "B", 7 },{ "E", 5 },{ "E", 3 },{ "E",1 } };
    printf("[new_container_classes] unordered_multimap 元素: {");
    for (auto pair : multimap_grades) {
        printf("[%s %d] ", pair.first.c_str(), pair.second);
    }
    printf("}.\n");
    printf("\n"); // 演示结束
}

// Feature name        : Tuple
// Feature description : 可以包含多种类型元素的对象,这些元素可以通过索引访问
// Demo description    : 显示 tuple 的基本使用,包括创建和访问
void ecall_tuple_demo()
{
    // 使用 std::make_tuple 创建 tuple
    char array_of_letters[4] = {'A','B','C','D'};
    std::vector<char> vector_of_letters = { 'A','B','C','D' };
    std::map<char, char> map_of_letters = { {'B','b' } };
    // 使用 tuple 构造函数创建 tuple
    std::tuple<int, std::string> tuple_sample_with_constructor(42, "Sample tuple");
    (void)tuple_sample_with_constructor;
    // 使用 std::make_tuple 创建 tuple
    auto tuple_sample = std::make_tuple("<TupleSample 的第一个元素>", 1, 7.9, vector_of_letters, array_of_letters, map_of_letters);
    // 使用 std::get<索引> 访问 tupleSample 中的元素
    printf("[tuple] 显示 TupleSample 中的第一个元素: %s.\n", std::get<0>(tuple_sample));
    printf("[tuple] 显示 TupleSample 中的第二个元素: %d.\n", std::get<1>(tuple_sample));
    printf("[tuple] 显示 TupleSample 中的第三个元素: %f.\n", std::get<2>(tuple_sample));
    // 从 tuple 中获取 vector
    std::vector<char> temp_vector = std::get<3>(tuple_sample);
    (void)temp_vector;
    // 从 tuple 中获取数组
    int first_elem_of_array = std::get<4>(tuple_sample)[0];
    (void)first_elem_of_array;
    // 从 tuple 中获取 map
    std::map<char, char> temp_map = std::get<5>(tuple_sample);
    (void)temp_map;
    printf("\n"); // 演示结束
}

// Feature name        : new smart pointers
// Feature description : shared_ptr 和 unique_ptr
// Demo description    : 显示智能指针的基本使用
// ecall_shared_ptr_demo 的辅助类
class DemoSmartPtr
{
    std::string smartPointerType;
public:
    DemoSmartPtr(std::string param_smartPointerType)
    {
        printf("[smart_ptr] 构造对象 DemoSmartPtr 使用 %s.\n", param_smartPointerType.c_str());
        this->smartPointerType = param_smartPointerType;
    }
    ~DemoSmartPtr()
    {
        printf("[smart_ptr] 析构对象 DemoSmartPtr 使用 %s.\n", smartPointerType.c_str());
    }
};

void ecall_shared_ptr_demo()
{
    // std::shared_ptr 是一个智能指针,使用引用计数管理对象的生命周期
    // 当最后一个智能指针不再指向它时,对象会被释放
    // 使用 std::make_shared 创建智能指针
    auto shared_ptr = std::make_shared<DemoSmartPtr>("shared_ptr.");
    printf("[smart_ptr] shared_ptr 的引用计数 = %ld.\n", shared_ptr.use_count());
    auto shared_ptr2 = shared_ptr;
    printf("[smart_ptr] 创建另一个智能指针后,shared_ptr 的引用计数 = %ld.\n", shared_ptr.use_count());
    shared_ptr2.reset();
    printf("[smart_ptr] 释放所有权后,shared_ptr 的引用计数 = %ld.\n", shared_ptr.use_count());
    // std::unique_ptr 是一个独占所有权的智能指针
    // 与 shared_ptr 不同,一旦独占指针指向对象,其他独占指针不能再指向相同对象
    std::unique_ptr<DemoSmartPtr> unique_ptr(new DemoSmartPtr("unique_ptr"));
    // 变量超出作用域时,both shared_ptr 和 unique_ptr 释放各自拥有的对象
    // 演示结束
}

// Feature name        : atomic
// Feature description : atomic 库提供细粒度的原子操作组件,允许无锁并发编程。
//                     每个原子操作与涉及同一对象的任何其他原子操作是不可分割的。
//                     原子对象是无数据竞争的。
// Demo description   : 显示 atomic 类型、对象和函数在信任域中的使用。
void ecall_atomic_demo()
{
    printf("[atomic] atomic 类型、对象和函数演示.\n");
    printf("[atomic_store] 定义一个初始值为 5 的 atomic_char 对象.\n");
    std::atomic_char atc(5);
    printf("[atomic_store] atomic 对象中当前存储的值是: %d\n", atc.load());
    printf("[atomic_store] 将 atomic 对象的值替换为非原子值 3.\n");
    std::atomic_store<char>(&atc, 3);
    printf("[atomic_store] atomic 对象的新值是: %d.\n", atc.load());
    printf("\n");
    printf("[atomic_store_explicit] 定义一个初始值为 5 的 atomic_short 对象.\n");
    std::atomic_short ats(5);
    printf("[atomic_store_explicit] atomic 对象中当前存储的值是: %d.\n", ats.load());
    printf("[atomic_store_explicit] 将 atomic 对象的值替换为非原子值 3.\n");
    std::atomic_store_explicit<short>(&ats, 3, std::memory_order_seq_cst);
    printf("[atomic_store] atomic 对象的新值是: %d.\n", ats.load());
    printf("\n");
    printf("[atomic_load] 定义一个初始值为 4 的 atomic_int 对象.\n");
    std::atomic_int ati1(4);
    printf("[atomic_load] 获取 atomic 对象的值并将其保存到 int 变量中.\n");
    int val = std::atomic_load(&ati1);
    printf("[atomic_load] 获取的值是 %d.\n", val);
    printf("\n");
    printf("[atomic_load_explicit] 定义一个初始值为 2 的 atomic_int 对象.\n");
    std::atomic_int ati2(2);
    printf("[atomic_load_explicit] 获取 atomic 对象的值并将其保存到 int 变量中.\n");
    int val1 = std::atomic_load_explicit(&ati2, std::memory_order_seq_cst);
    printf("[atomic_load_explicit] 获取的值是 %d.\n", val1);
    printf("\n");
    printf("[atomic_fetch_add] 定义一个初始值为 7 的 atomic_int 对象.\n");
    std::atomic_int ati(7);
    printf("[atomic_fetch_add] atomic 对象中当前存储的值是: %d.\n", ati.load());
    printf("[atomic_fetch_add] 将非原子值 8 添加到 atomic 对象中.\n");
    std::atomic_fetch_add(&ati, 8);
    printf("[atomic_fetch_add] atomic 对象的新值是: %d.\n", ati.load());
    printf("\n");
    printf("[atomic_fetch_add_explicit] 定义一个初始值为 7 的 atomic_uint 对象.\n");
    std::atomic_uint atui(7);
    printf("[atomic_fetch_add_explicit] atomic 对象中当前存储的值是: %u.\n", atui.load());
    printf("[atomic_fetch_add_explicit] 将非原子值 8 添加到 atomic 对象中.\n");
    std::atomic_fetch_add_explicit<unsigned int>(&atui, 8, std::memory_order_seq_cst);
    printf("[atomic_fetch_add_explicit] atomic 对象的新值是: %u.\n", atui.load());
    printf("\n");
    printf("[atomic_fetch_sub] 定义一个初始值为 20 的 atomic_long 对象.\n");
    std::atomic_long atl(20);
    printf("[atomic_fetch_sub] atomic 对象中当前存储的值是: %ld.\n", atl.load());
    printf("[atomic_fetch_sub] 从 atomic 对象的值中减去非原子值 8.\n");
    std::atomic_fetch_sub<long>(&atl, 8);
    printf("[atomic_fetch_sub] atomic 对象的新值是: %ld.\n", atl.load());
    printf("\n");
    printf("[atomic_fetch_sub_explicit] 定义一个初始值为 20 的 atomic_llong 对象.\n");
    std::atomic_llong atll(20);
    printf("[atomic_fetch_sub_explicit] atomic 对象中当前存储的值是: %lld.\n", atll.load());
    printf("[atomic_fetch_sub_explicit] 从 atomic 对象的值中减去非原子值 8.\n");
    std::atomic_fetch_sub_explicit<long long>(&atll, 8, std::memory_order_seq_cst);
    printf("[atomic_fetch_sub_explicit] atomic 对象的新值是: %lld.\n", atll.load());
    printf("\n"); // 演示结束
}

// Feature name        : mutex
// Feature description : mutex 类是一个同步原语,可以用来保护共享数据
//                     防止多个线程同时访问数据。
// Demo description    : 显示在多个线程中增量值时的 mutex 保护。
// 用于演示没有使用 mutex 的行为的结构
struct CounterWithoutMutex {
    int value;
    CounterWithoutMutex() : value(0) {}
    void increment() {
        ++value;
    }
};
CounterWithoutMutex counter_without_protection;
// 演示没有使用 mutex 保护的计数器增量的 E-call
void ecall_mutex_demo_no_protection()
{
    for (int i = 0; i < 100000; ++i) {
        counter_without_protection.increment();
    }
}

// 用于获取最终值没有使用 mutex 保护的计数器的 E-call
void ecall_print_final_value_no_protection()
{
    printf("[mutex] 在三个线程中没有 mutex 保护的增量,使用 100000 次循环。\n[mutex] 预期值是 300000。最终值是 %d.\n", counter_without_protection.value);
}
// 用于演示 mutex 保护的结构
struct CounterProtectedByMutex {
    std::mutex mutex;
    int value;
    CounterProtectedByMutex() : value(0) {}
    void increment() {
        // 加锁以防止在不同线程中的同时增量
        mutex.lock();
        ++value;
        // 释放锁
        mutex.unlock();
    }
};
CounterProtectedByMutex counter_with_protection;
// 演示实际增量操作的 E-call
void ecall_mutex_demo()
{
    for (int i = 0; i < 100000; ++i) {
        counter_with_protection.increment();
    }
}

// 用于获取最终值有 mutex 保护的计数器的 E-call
void ecall_print_final_value_mutex_demo()
{
    printf("[mutex] 在三个线程中使用 mutex 保护的增量,使用 100000 次循环。\n[mutex] 预期值是 300000。最终值是 %d.\n", counter_with_protection.value);
}

// Feature name       : condition_variable
// Feature description: condition_variable 类是一个同步原语,可以用来阻塞一个线程,
//                     或同时阻塞多个线程,直到另一个线程修改共享变量(条件)
//                     并通知 condition_variable。
// Demo description   : 演示在两个线程环境中使用 condition_variable。一个线程用于加载数据,
//                     另一个线程处理加载的数据。处理数据的线程等待数据加载线程完成加载,
//                     并在加载完成后收到通知。
class DemoConditionVariable   // condition_variable 演示使用的类
{
    std::mutex mtx;
    std::condition_variable cond_var;
    bool data_loaded;
public:
    DemoConditionVariable()
    {
        data_loaded = false;
    }
    void load_data()
    {
        // 模拟数据加载
        printf("[condition_variable] 正在加载数据...\n");
        {
            // 加锁数据结构
            std::lock_guard<std::mutex> guard(mtx);
            // 设置标志为 true,表示数据加载完成
            data_loaded = true;
        }
        // 通知解锁等待中的线程
        cond_var.notify_one();
    }
    bool is_data_loaded()
    {
        return data_loaded;
    }
    void main_task()
    {
        printf("\n");
        printf("[condition_variable] 运行 condition variable 演示。\n");
        // 获取锁
        std::unique_lock<std::mutex> lck(mtx);
        printf("[condition_variable] 正在等待另一个线程加载数据。\n");
        cond_var.wait(lck, std::bind(&DemoConditionVariable::is_data_loaded, this));
        printf("[condition_variable] 处理已加载的数据。\n");
        printf("[condition_variable] 完成。\n");
    }
};
DemoConditionVariable app;
// condition_variable 演示用到的 E-call - 数据处理线程
void ecall_condition_variable_run()
{
    app.main_task();
}
// condition_variable 演示用到的 E-call - 数据加载线程
void ecall_condition_variable_load()
{
    app.load_data();
}

1.2.5 Enclave/Enclave.cpp+Enclave.h

  • Enclave.h
#ifndef _ENCLAVE_H_
#define _ENCLAVE_H_
#include <stdlib.h>
#include <assert.h>
#if defined(__cplusplus)
extern "C" {
#endif
// printf函数,调用REE中OCALL函数完成打印,很重要,自己调试TEE程序时需要打印!!!
int printf(const char *fmt, ...);   
#if defined(__cplusplus)
}
#endif
#endif /* !_ENCLAVE_H_ */
  • Enclave.cpp
#include <stdarg.h>
#include <stdio.h>      /* vsnprintf */
#include "Enclave.h"
#include "Enclave_t.h"  /* print_string */
/* 
 * printf: 
 *   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);   // 在App.cpp中定义的:ocall_print_string(const char *str)
    return 0;
}

    这里面需要注意的只有一点,就是我们在调试enclave中程序时,printf是一个重要的调试手段,但是在enclave无法直接调用printf函数,也不安全,因此此处采用OCALL函数调用的方式将需要打印的内容通过buffer传入到REE中打印出来,值得我们在后续程序设计中借鉴!!!

1.3 编译执行

make
./app

执行结果:

[Lambdas] 初始数组使用 lambdas: { 0 1 2 3 4 5 6 7 8 9 10 }.
[Lambdas] 数组中的第一个奇数是 1. 
[Lambdas] 数组中的偶数数量是 6.
[Lambdas] 排序后的数组: { 10 9 8 7 6 5 4 3 2 1 0 }. 

[auto] a 的类型是 int. typeid = i.
[auto] b1 的类型是 const double. typeid = d.
[auto] b2 的类型是 const double*. typeid = PKd.
[auto] c 的类型是 int. typeid = i.
[auto] d 的类型是 int*. typeid = Pi.
[auto] lambda 的类型是 [] {}. typeid = *Z15ecall_auto_demoEUlvE_.
[auto] func 的类型是 void(__cdecl*)(void). typeid = PFvvE.
[auto] 调用函数 sample_func_auto_demo.

[decltype] b 的类型是 int. typeid = i.
[decltype] sum 的类型是 double. typeid = d.

[range_based_for_loops] 使用 range based for loop 打印数组内容: { a b c d }. 
[range_based_for_loops] 使用 range based for loop 打印 vector 内容: { a b c d }.

[delegating constructors] 调用自 DemoDelegatingConstructors(int a, int b, int c).
[delegating constructors] 调用自 DemoDelegatingConstructors(int a, int b).
[delegating constructors] 调用自 DemoDelegatingConstructors(int a).

[std_function] 调用 sample_std_function1
[std_function] 调用一个 lambda 函数

[cxx11_algorithms] 所有元素在 { 0 1 2  3 4 5 } 中都是偶数是 false.
[cxx11_algorithms] { 0 1 2 3 4 5 } 中的一些元素为偶数是 true.
[cxx11_algorithms] { 0 1 2 3 4 5 } 中无元素为偶数是 false.

[variadic_templates] 参数 (1, 2, 3, 4, 5) 的和是 15.

[sfinae] 第二个替换候选者匹配.

[initializer_list] 在构造函数中使用初始化列表.
[initializer_list] 向量中的元素是: 10 9 8 7 6 5 4 3 2 1.

[rvalue] DemoBuffer a(100).
[rvalue] 调用构造函数 : DemoBuffer(int size).
[rvalue] 调用 foobar(100). 
[rvalue] 调用构造函数 : DemoBuffer(int size).
[rvalue] 调用构造函数 : DemoBuffer(int size).
[rvalue] 调用移动构造函数 : DemoBuffer(DemoBuffer && rhs).
[rvalue] DemoBuffer b(a).
[rvalue] 调用拷贝构造函数 : DemoBuffer(const DemoBuffer &rhs).
[rvalue] DemoBuffer c(std::move(a)).
[rvalue] 调用移动构造函数 : DemoBuffer(DemoBuffer && rhs).

[nullptr] 调用了 void nullptr_overload_candidate(int i).
[nullptr] 调用了 void nullptr_overload_candidate(int* ptr).
[nullptr] 调用了函数 g
[nullptr] 调用了函数 g
[nullptr] 调用了函数 g

[enum class] brown - int = 1
[enum class] red - int = 32
[enum class] green - int = 30

[new_container_classes] unordered_set { 0, 1, 2, 3, 4, 5} 包含值 3.
[new_container_classes] unordered_multiset { 0, 1, 2, 3, 3, 3} 包含 3 个值 3.
[new_container_classes] unordered_map 元素: {[E 3] [D 5] [C 7] [B 8] [A 10] }.
[new_container_classes] unordered_multimap 元素: {[E 5] [E 3] [E 1] [B 8] [B 7] [A 10] }.

[tuple] 显示 TupleSample 中的第一个元素: <TupleSample 的第一个元素>.
[tuple] 显示 TupleSample 中的第二个元素: 1.
[tuple] 显示 TupleSample 中的第三个元素: 7.900000.

[smart_ptr] 构造对象 DemoSmartPtr 使用 shared_ptr..
[smart_ptr] shared_ptr 的引用计数 = 1.
[smart_ptr] 创建另一个智能指针后,shared_ptr 的引用计数 = 2.
[smart_ptr] 释放所有权后,shared_ptr 的引用计数 = 1.
[smart_ptr] 构造对象 DemoSmartPtr 使用 unique_ptr.
[smart_ptr] 析构对象 DemoSmartPtr 使用 unique_ptr.
[smart_ptr] 析构对象 DemoSmartPtr 使用 shared_ptr..
[atomic] atomic 类型、对象和函数演示.
[atomic_store] 定义一个初始值为 5 的 atomic_char 对象.
[atomic_store] atomic 对象中当前存储的值是: 5
[atomic_store] 将 atomic 对象的值替换为非原子值 3.
[atomic_store] atomic 对象的新值是: 3.

[atomic_store_explicit] 定义一个初始值为 5 的 atomic_short 对象.
[atomic_store_explicit] atomic 对象中当前存储的值是: 5.
[atomic_store_explicit] 将 atomic 对象的值替换为非原子值 3.
[atomic_store] atomic 对象的新值是: 3.

[atomic_load] 定义一个初始值为 4 的 atomic_int 对象.
[atomic_load] 获取 atomic 对象的值并将其保存到 int 变量中.
[atomic_load] 获取的值是 4.

[atomic_load_explicit] 定义一个初始值为 2 的 atomic_int 对象.
[atomic_load_explicit] 获取 atomic 对象的值并将其保存到 int 变量中.
[atomic_load_explicit] 获取的值是 2.

[atomic_fetch_add] 定义一个初始值为 7 的 atomic_int 对象.
[atomic_fetch_add] atomic 对象中当前存储的值是: 7.
[atomic_fetch_add] 将非原子值 8 添加到 atomic 对象中.
[atomic_fetch_add] atomic 对象的新值是: 15.

[atomic_fetch_add_explicit] 定义一个初始值为 7 的 atomic_uint 对象.
[atomic_fetch_add_explicit] atomic 对象中当前存储的值是: 7.
[atomic_fetch_add_explicit] 将非原子值 8 添加到 atomic 对象中.
[atomic_fetch_add_explicit] atomic 对象的新值是: 15.

[atomic_fetch_sub] 定义一个初始值为 20 的 atomic_long 对象.
[atomic_fetch_sub] atomic 对象中当前存储的值是: 20.
[atomic_fetch_sub] 从 atomic 对象的值中减去非原子值 8.
[atomic_fetch_sub] atomic 对象的新值是: 12.

[atomic_fetch_sub_explicit] 定义一个初始值为 20 的 atomic_llong 对象.
[atomic_fetch_sub_explicit] atomic 对象中当前存储的值是: 20.
[atomic_fetch_sub_explicit] 从 atomic 对象的值中减去非原子值 8.
[atomic_fetch_sub_explicit] atomic 对象的新值是: 12.

[mutex] 在三个线程中没有 mutex 保护的增量,使用 100000 次循环。
[mutex] 预期值是 300000。最终值是 103921.
[mutex] 在三个线程中使用 mutex 保护的增量,使用 100000 次循环。
[mutex] 预期值是 300000。最终值是 300000.

[condition_variable] 正在加载数据...
[condition_variable] 运行 condition variable 演示。
[condition_variable] 正在等待另一个线程加载数据。
[condition_variable] 处理已加载的数据。
[condition_variable] 完成。
Info: Cxx11DemoEnclave successfully returned.

1.4 总结

    官方的例子功能十分丰富,我们开发者要做的就是从例子中学习如何在enclave中开发自己想要的功能,形成标准的模块方法,并参考例子中的一些标准用法,后续将更新更多例子,展示更多功能,逐渐形成自己的enclave代码库!

示例二. Cxx14SGXDemo

基本流程与上一致,后续补充c++14新特性在enclave中的执行测试…

示例三. Cxx17SGXDemo

基本流程与上一致,后续补充c++17新特性在enclave中的执行测试…

四. 参考链接

Intel-SGX:SampleCode/Cxx11SGXDemo

五. 感谢支持

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot集成道历(实现道历日期查询)

官网地址&#xff1a;官网地址https://6tail.cn/calendar/api.html 1、导入依赖 <dependency><groupId>cn.6tail</groupId><artifactId>lunar</artifactId><version>1.3.9</version></dependency><dependency><group…

斜光测距的原理及python实现

1.前言 最近做了一个基于opencv的斜光测距的小项目&#xff0c;东西不多&#xff0c;但是很有意思&#xff0c;值得拿出来学一学。项目里面需要比较精确的定位功能&#xff0c;将前人matlab代码移植到python上&#xff0c;并且做了一些优化&#xff0c;简化逻辑(毕竟我是专业的…

uView 2.0:uni-app生态的利剑出鞘,引领UI框架新纪元

引言 随着移动互联网的快速发展&#xff0c;跨平台应用开发成为了开发者们关注的焦点。uni-app&#xff0c;一个基于Vue.js的跨平台应用开发框架&#xff0c;因其高效、易用的特性而广受欢迎。在uni-app的生态系统中&#xff0c;UI框架的选择对于开发者而言至关重要。今天&…

AI 编程探索- iOS动态标签控件

需求分析&#xff1a; 标签根据文字长度&#xff0c;自适应标签居中显示扩展 超过内容显示范围&#xff0c;需要换行显示&#xff0c;且保持居中显示 AI实现过程 提问&#xff1a; 回答&#xff1a; import UIKit import SnapKitclass DynamicLabelsContainerView: UIView…

docker 多网卡指定网卡出网

前言 宿主机中有多个网卡 ens160 192.168.4.23/20 内网通信用 ens192 10.31.116.128/24 出公网访问-1 ens193 10.31.116.128/24 出公网访问-2 现在需要不同容器中不同出网访问&#xff0c;举例 容器1 192.168.0.1/20 网段走宿主机 ens160网卡&#xff0c;否则全部走ens192 网…

CAS自旋解析

CAS全称CompareAndSwap(比较并交换)&#xff0c;是cpu的指令&#xff0c;调用时不涉及上下文的切换。Java中属于乐观锁的一种&#xff0c;具体流程如下图&#xff1a; 具体的实现使用的是Unsafe类去调用native修饰的compareAndSwap方法&#xff0c;4个字段分别是对象实例&#…

Shell编程实战

脚本编程步骤 脚本编程一般分为以下几个步骤: 需求分析:根据系统管理的需求&#xff0c;分析脚本要实现的功能、功能实现的层次、实现的命令与语句等; 命令测试:将要用到的命令逐个进行测试&#xff0c;以决定使用的选项、要设置的变量等: 脚本编程:将测试好的命令写入到脚本文…

庆祝东兴市金顺心贸易有限公司代理越南三原竹系列产品五周年

&#x1f389;庆祝金顺心贸易代理越南三原竹系列产品五周年&#xff01;这五年&#xff0c;我们共同成长&#xff0c;每一份产品都承载着越南的美味与匠心。感恩有你们&#xff0c;未来的路&#xff0c;我们继续携手前行&#xff0c;品味更多美好&#xff01;&#x1f962;&…

电子名片小程序源码系统 前后端分离 带完整的安装代码包以及搭建教程

系统概述 电子名片小程序源码系统是一款基于前后端分离架构的综合性平台&#xff0c;旨在为用户提供一个集销售名片和企业商城于一体的解决方案。该系统采用先进的技术手段&#xff0c;实现了个性化名片设计、便捷的销售功能、企业商城模块等一系列实用功能。同时&#xff0c;…

vue-cli 搭建项目

创建 router 目录 在一个.js文件中添加 打开外部命令 打开外部命令后&#xff0c;在指令栏输入npm i vue-router3.5.3 &#xff0c;等待下载 下载完成后 在 main.js 中配置路由 输入这些后&#xff0c;基本的配置就实现了 最后进行测试&#xff0c;验证是否配置 或者打开外部命…

springcloud第4季 分布式事务seata作用服务搭建1

一 seata作用 1.1 seata简介 1.seata是一款解决分布式事务的解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 1.2 seata的术语 一个中心&#xff1a;全局事务id&#xff0c;xid&#xff0c;在调用服务链路的上下文中进行传播。TC(Transa…

iPhone怎么恢复删除的数据?几款顶级iPhone数据恢复软件

从iOS设备恢复数据。 对于任何数据恢复软件来说&#xff0c;从iOS设备恢复数据都是一项复杂的任务&#xff0c;因为Apple已将众多数据保护技术集成到现代iPhone和iPad中。其中包括硬件加密和文件级加密。iOS 上已删除的数据只能通过取证文件工件搜索来找到&#xff0c;例如分析…

最新扣子(Coze)实战案例:图像流工具之空间风格化,完全免费教程

&#x1f9d9;‍♂️ 大家好&#xff0c;我是斜杠君&#xff0c;手把手教你搭建扣子AI应用。 &#x1f4dc; 本教程是《AI应用开发系列教程之扣子(Coze)实战教程》&#xff0c;完全免费学习。 &#x1f440; 关注斜杠君&#xff0c;可获取完整版教程。&#x1f44d;&#x1f3f…

EHS,制造业安全绿色生产的隐形守护神

当我们提到EHS&#xff0c;可能很多人会稍感陌生&#xff0c;毕竟它不是一个日常生活中经常提及的词汇。但实际上&#xff0c;EHS在我们的生活和工作中扮演着极其重要的角色&#xff0c;尤其对制造业而言更是可持续发展经营管理的重中之重。 一、EHS是什么意思&#xff1f; E…

vue项目内网部署流程

由于第一次部署&#xff0c;也是第一次自己用 Nginx , 百度了很久&#xff0c;没有看到想看的步骤&#xff0c;所以作此文以记录&#xff0c;也是给像我一样的人一个大概方向。 注&#xff1a;windows系统 1、首先要弄好jar包的运行环境。 安装jdk 详细安装过程引用 jdk的完整…

码农:如何快速融入团队

问题&#xff1a; 码农如何快速融入团队&#xff1f; 记住一个标准&#xff1a;能干事、能抗事。 总结一个字&#xff1a; 靠谱。 适用范围&#xff1a;新手码农、老司机码农、测试、DBA、运维、产品经理、项目经理、架构师、技术专家、。。。。适用于任何行业的打工者。 下面要…

伙伴活动推荐丨当 RTC 遇上 AI ,大模型创新应用星城论道

近年来&#xff0c;音视频技术已成为推动在线新经济和企业数字化转型的重要力量。作为中部互联网产业高地&#xff0c;湖南长沙亦将音视频产业视为战略性新兴产业重点布局。 2024年7月6日&#xff0c;声网联合 CSDN 在湖南长沙举办声网城市沙龙&#xff0c;以“当 RTC 遇上 AI…

VMware Workstation环境下,DHCP服务的安装配置,用ubuntu来测试

需求说明: 某企业信息中心计划使用IP地址17216.11.0用于虚拟网络测试,注册域名为xyz.net.cn.并将172.16.11.2作为主域名的服务器(DNS服务器)的IP地址,将172.16.11.3分配给虚拟网络测试的DHCP服务器,将172.16.11.4分配给虚拟网络测试的web服务器,将172.16.11.5分配给FTP服务器…

Matlab/simulink三段式电流保护

电流1段仿真波形如下所示 电流2段仿真波形如下所示 电流3段仿真波形如下所示

SSL证书在网站访问中的核心作用及快速申请指南

在当今的互联网时代&#xff0c;数据安全与用户隐私保护成为了网站运营不可或缺的一部分。SSL证书作为一种重要的网络安全协议&#xff0c;它在网站访问中扮演着至关重要的角色&#xff0c;主要体现在以下几个方面&#xff1a; 一、加密通信内容&#xff1a;SSL证书通过建立安…