forked from espressif/esp-idf
refactor(esp_tee): Add argument count checks for secure services in the dispatcher
Also: - Unified the TEE build system-related scripts into a single script
This commit is contained in:
@@ -82,57 +82,38 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(secure_service_hdr_py
|
set(secure_service_tbl_parser_py
|
||||||
${COMPONENT_DIR}/scripts/secure_service_hdr.py ${CMAKE_CURRENT_BINARY_DIR}/secure_service.tbl
|
${COMPONENT_DIR}/scripts/secure_service_tbl_parser.py ${CMAKE_CURRENT_BINARY_DIR}/secure_service.tbl
|
||||||
)
|
)
|
||||||
|
|
||||||
set(secure_service_tbl_py
|
set(secure_service_gen_headers
|
||||||
${COMPONENT_DIR}/scripts/secure_service_tbl.py ${CMAKE_CURRENT_BINARY_DIR}/secure_service.tbl
|
${CONFIG_DIR}/secure_service_num.h ${CONFIG_DIR}/secure_service_dec.h
|
||||||
)
|
|
||||||
|
|
||||||
set(secure_service_wrap_py
|
|
||||||
${COMPONENT_DIR}/scripts/secure_service_wrap.py ${CMAKE_CURRENT_BINARY_DIR}/secure_service.tbl
|
|
||||||
)
|
|
||||||
|
|
||||||
set(secure_service_num_h
|
|
||||||
${CONFIG_DIR}/secure_service_num.h
|
|
||||||
)
|
|
||||||
set(secure_service_dec_h
|
|
||||||
${CONFIG_DIR}/secure_service_dec.h)
|
|
||||||
|
|
||||||
set(secure_service_h
|
|
||||||
${CONFIG_DIR}/secure_service.h
|
${CONFIG_DIR}/secure_service.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(CONFIG_SECURE_ENABLE_TEE)
|
if(CONFIG_SECURE_ENABLE_TEE AND NOT esp_tee_build)
|
||||||
execute_process(COMMAND cat ${COMPONENT_DIR}/scripts/${target}/secure_service.tbl ${custom_secure_service_tbl}
|
execute_process(
|
||||||
|
COMMAND cat ${COMPONENT_DIR}/scripts/${target}/secure_service.tbl ${custom_secure_service_tbl}
|
||||||
OUTPUT_FILE secure_service.tbl
|
OUTPUT_FILE secure_service.tbl
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
execute_process(COMMAND python ${secure_service_hdr_py} ${secure_service_num_h} ${secure_service_dec_h}
|
execute_process(
|
||||||
|
COMMAND python ${secure_service_tbl_parser_py} ${secure_service_gen_headers}
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
execute_process(COMMAND python ${secure_service_tbl_py} ${secure_service_h}
|
set_property(DIRECTORY ${COMPONENT_DIR} APPEND PROPERTY
|
||||||
|
ADDITIONAL_MAKE_CLEAN_FILES ${secure_service_gen_headers}
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND python ${secure_service_tbl_parser_py} "--wrap"
|
||||||
|
OUTPUT_VARIABLE wrap_list
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
|
||||||
set_property(DIRECTORY "${COMPONENT_DIR}" APPEND PROPERTY
|
string(STRIP "${wrap_list}" wrap_list)
|
||||||
ADDITIONAL_MAKE_CLEAN_FILES ${secure_service_num_h} ${secure_service_dec_h} ${secure_service_h})
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "${wrap_list}")
|
||||||
|
|
||||||
# For TEE implementation, we don't wrap the APIs since the TEE would also internally use the same API and
|
|
||||||
# it shouldn't route to secure service API.
|
|
||||||
# Instead of wrapping, we append _ss_* to the API name and then it must be defined in esp_secure_services.c
|
|
||||||
if(NOT esp_tee_build)
|
|
||||||
execute_process(COMMAND python ${secure_service_wrap_py}
|
|
||||||
OUTPUT_VARIABLE wrap_list
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
|
|
||||||
string(STRIP ${wrap_list} wrap_list)
|
|
||||||
|
|
||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "${wrap_list}")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
@@ -1,76 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
import argparse
|
|
||||||
import re
|
|
||||||
from typing import List
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
|
|
||||||
def parse_services(secure_service_tbl: str) -> List[Tuple[str, str, str]]:
|
|
||||||
services: List[Tuple[str, str, str]] = []
|
|
||||||
pattern: re.Pattern = re.compile(r'^([0-9A-Fa-fXx]+)\s+\S+\s+(\S+)\s+(\d+)')
|
|
||||||
with open(secure_service_tbl, 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
if match := pattern.match(line):
|
|
||||||
services.append((match.group(1), match.group(2), match.group(3)))
|
|
||||||
return sorted(services, key=lambda x: int(x[0]))
|
|
||||||
|
|
||||||
|
|
||||||
def generate_num_header(services: List[Tuple[str, str, str]], output_file: str) -> None:
|
|
||||||
header_text: str = '''/**
|
|
||||||
* This header file is used to generate secure service number macros.
|
|
||||||
*
|
|
||||||
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
'''
|
|
||||||
with open(output_file, 'w') as f:
|
|
||||||
f.write(header_text)
|
|
||||||
for nr, name, _ in services:
|
|
||||||
f.write(f'#define SS_{name.upper()}\t{nr}\n')
|
|
||||||
total: int = int(services[-1][0]) + 1 if services else 0
|
|
||||||
f.write(f'\n#define MAX_SECURE_SERVICES\t{total}\n\n')
|
|
||||||
|
|
||||||
|
|
||||||
def generate_dec_header(services: List[Tuple[str, str, str]], output_file: str) -> None:
|
|
||||||
header_text: str = '''/**
|
|
||||||
* This header file is used to provide function declarations
|
|
||||||
* for compiling secure_service_table.c source file. Please do not
|
|
||||||
* use it in application.
|
|
||||||
*
|
|
||||||
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
'''
|
|
||||||
with open(output_file, 'w') as f:
|
|
||||||
f.write(header_text)
|
|
||||||
for _, name, _ in services:
|
|
||||||
f.write(f'void _ss_{name}(void);\n')
|
|
||||||
f.write('''
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
''')
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
parser = argparse.ArgumentParser(description='Generate secure service headers')
|
|
||||||
parser.add_argument('secure_service_tbl', type=str, help='Path to secure_service.tbl generated in build directory')
|
|
||||||
parser.add_argument('secure_service_num_h', type=str, help='Path to secure_service_num.h header file')
|
|
||||||
parser.add_argument('secure_service_dec_h', type=str, help='Path to secure_service_dec.h header file')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
services: List[Tuple[str, str, str]] = parse_services(args.secure_service_tbl)
|
|
||||||
generate_num_header(services, args.secure_service_num_h)
|
|
||||||
generate_dec_header(services, args.secure_service_dec_h)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@@ -1,50 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
import argparse
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from typing import Dict
|
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
|
|
||||||
def emit(nr: int, entry: str, nargs: str) -> str:
|
|
||||||
return f'__SECURE_SERVICE({nr}, {entry}, {nargs})'
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
parser = argparse.ArgumentParser(description='Generate secure service table')
|
|
||||||
parser.add_argument('input_file', type=str, help='Path to input file')
|
|
||||||
parser.add_argument('output_file', type=str, help='Path to output file')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
services: Dict[int, Tuple[str, str, str]] = {}
|
|
||||||
pattern: re.Pattern = re.compile(r'^([0-9A-Fa-fXx]+)\s+(\S+)\s+(\S+)\s+(\d+)')
|
|
||||||
|
|
||||||
# Single pass through file to collect services and check duplicates
|
|
||||||
with open(args.input_file, 'r') as f:
|
|
||||||
for line in f:
|
|
||||||
if match := pattern.match(line):
|
|
||||||
nr = int(match.group(1))
|
|
||||||
if nr in services:
|
|
||||||
print('ERROR: Found duplicate secure service numbers, exiting...')
|
|
||||||
sys.exit(1)
|
|
||||||
services[nr] = (match.group(2), match.group(3), match.group(4))
|
|
||||||
|
|
||||||
# Generate output
|
|
||||||
with open(args.output_file, 'w') as f:
|
|
||||||
f.write('''/**
|
|
||||||
* This header file is used to define secure services.
|
|
||||||
*
|
|
||||||
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
''')
|
|
||||||
for nr in sorted(services):
|
|
||||||
_, name, nargs = services[nr]
|
|
||||||
f.write(emit(nr, name, nargs) + '\n')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
104
components/esp_tee/scripts/secure_service_tbl_parser.py
Normal file
104
components/esp_tee/scripts/secure_service_tbl_parser.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
from typing import List
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
|
def parse_services(secure_service_tbl: str) -> List[Tuple[int, str, int]]:
|
||||||
|
services, service_ids = [], set()
|
||||||
|
pattern = re.compile(r'^([0-9A-Fa-fXx]+)\s+\S+\s+(\S+)\s+(\d+)')
|
||||||
|
|
||||||
|
with open(secure_service_tbl, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if match := pattern.match(line):
|
||||||
|
service_id = int(match.group(1), 0)
|
||||||
|
if service_id in service_ids:
|
||||||
|
raise ValueError(f'Duplicate service call ID found: 0x{service_id:X}')
|
||||||
|
service_ids.add(service_id)
|
||||||
|
services.append((service_id, match.group(2), int(match.group(3))))
|
||||||
|
|
||||||
|
return sorted(services, key=lambda x: x[0])
|
||||||
|
|
||||||
|
|
||||||
|
def generate_num_header(services: List[Tuple[int, str, int]], output_file: str) -> None:
|
||||||
|
header = '''/**
|
||||||
|
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
'''
|
||||||
|
body = '\n'.join(f'#define SS_{name.upper()}\t{nr}' for nr, name, _ in services)
|
||||||
|
footer = f'\n#define MAX_SECURE_SERVICES_ID\t{services[-1][0] + 1 if services else 0}\n'
|
||||||
|
footer += f'#define SECURE_SERVICES_NUM\t{len(services)}\n\n'
|
||||||
|
footer += '''typedef void (*secure_service_t)(void);
|
||||||
|
typedef struct { int id; secure_service_t func; int nargs; } secure_service_entry_t;
|
||||||
|
'''
|
||||||
|
footer += '\n#ifdef __cplusplus\n}\n#endif\n'
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(header + body + footer)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_dec_header(services: List[Tuple[int, str, int]], output_file: str) -> None:
|
||||||
|
header = '''/**
|
||||||
|
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
'''
|
||||||
|
body = '\n'.join(f'void _ss_{name}(void);' for _, name, _ in services)
|
||||||
|
footer = '\n#ifdef __cplusplus\n}\n#endif\n'
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(header + body + footer)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_table(services: List[Tuple[int, str, int]], output_file: str) -> None:
|
||||||
|
header = '''/**
|
||||||
|
* THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
'''
|
||||||
|
body = '\n'.join(f'__SECURE_SERVICE({nr}, {name}, {nargs})' for nr, name, nargs in services)
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(header + body)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_wrap_list(secure_service_tbl: str) -> None:
|
||||||
|
pattern = re.compile(r'^[0-9A-Fa-fXx]+\s+IDF\s+(\S+)\s+\d+')
|
||||||
|
with open(secure_service_tbl, 'r') as f:
|
||||||
|
wrap_list = [f'-Wl,--wrap={match.group(1)}' for line in f if (match := pattern.match(line))]
|
||||||
|
print(' '.join(wrap_list), end='')
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description='Generate secure service outputs')
|
||||||
|
parser.add_argument('--wrap', action='store_true', help='Generate linker wrap options')
|
||||||
|
parser.add_argument('secure_service_tbl', type=str, help='Path to secure service table file')
|
||||||
|
parser.add_argument('output_files', nargs='*', help='Output files: [secure_service_num.h, secure_service_dec.h, secure_service.h]')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.wrap:
|
||||||
|
generate_wrap_list(args.secure_service_tbl)
|
||||||
|
else:
|
||||||
|
if len(args.output_files) != 3:
|
||||||
|
parser.error('Missing output header files!')
|
||||||
|
services = parse_services(args.secure_service_tbl)
|
||||||
|
generate_num_header(services, args.output_files[0])
|
||||||
|
generate_dec_header(services, args.output_files[1])
|
||||||
|
generate_table(services, args.output_files[2])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@@ -1,24 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
import argparse
|
|
||||||
import re
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
parser = argparse.ArgumentParser(description='Generate secure service wrap list')
|
|
||||||
parser.add_argument('secure_service_tbl', type=str, help='Path to secure service table file')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
pattern: re.Pattern = re.compile(r'^[0-9A-Fa-fXx]+\s+IDF\s+(\S+)\s+\d+')
|
|
||||||
|
|
||||||
with open(args.secure_service_tbl, 'r') as f:
|
|
||||||
wrap_list: List[str] = [f'-Wl,--wrap={match.group(1)}'
|
|
||||||
for line in f if (match := pattern.match(line))]
|
|
||||||
|
|
||||||
print(' '.join(wrap_list), end='')
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@@ -13,6 +13,34 @@
|
|||||||
|
|
||||||
static const char *TAG = "esp_tee_sec_disp";
|
static const char *TAG = "esp_tee_sec_disp";
|
||||||
|
|
||||||
|
extern const secure_service_entry_t tee_secure_service_table[];
|
||||||
|
|
||||||
|
/* ---------------------------------------------- Secure Service Dispatcher ------------------------------------------------- */
|
||||||
|
|
||||||
|
const secure_service_entry_t *find_service_by_id(uint32_t id)
|
||||||
|
{
|
||||||
|
if (id >= MAX_SECURE_SERVICES_ID) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t left = 0;
|
||||||
|
size_t right = SECURE_SERVICES_NUM;
|
||||||
|
|
||||||
|
while (left < right) {
|
||||||
|
size_t mid = left + (right - left) / 2;
|
||||||
|
|
||||||
|
if (tee_secure_service_table[mid].id == id) {
|
||||||
|
return &tee_secure_service_table[mid];
|
||||||
|
} else if (tee_secure_service_table[mid].id < id) {
|
||||||
|
left = mid + 1;
|
||||||
|
} else {
|
||||||
|
right = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Entry point to the TEE binary during secure service call. It decipher the call and dispatch it
|
* @brief Entry point to the TEE binary during secure service call. It decipher the call and dispatch it
|
||||||
* to corresponding Secure Service API in secure world.
|
* to corresponding Secure Service API in secure world.
|
||||||
@@ -30,19 +58,25 @@ int esp_tee_service_dispatcher(int argc, va_list ap)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
void *fp_secure_service;
|
|
||||||
uint32_t argv[ESP_TEE_MAX_INPUT_ARG], *argp;
|
uint32_t argv[ESP_TEE_MAX_INPUT_ARG], *argp;
|
||||||
|
|
||||||
uint32_t sid = va_arg(ap, uint32_t);
|
uint32_t sid = va_arg(ap, uint32_t);
|
||||||
argc--;
|
argc--;
|
||||||
|
|
||||||
if (sid >= MAX_SECURE_SERVICES) {
|
const secure_service_entry_t *service = find_service_by_id(sid);
|
||||||
ESP_LOGE(TAG, "Invalid Service ID!");
|
if (service == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Invalid service ID!");
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return -1;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_secure_service = (void *)tee_secure_service_table[sid];
|
if (argc != service->nargs) {
|
||||||
|
ESP_LOGE(TAG, "Invalid number of arguments for service %d!", sid);
|
||||||
|
va_end(ap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *fp_secure_service = (void *)service->func;
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
argv[i] = va_arg(ap, uint32_t);
|
argv[i] = va_arg(ap, uint32_t);
|
||||||
@@ -107,4 +141,5 @@ int esp_tee_service_dispatcher(int argc, va_list ap)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -8,17 +8,13 @@
|
|||||||
#include "secure_service_num.h"
|
#include "secure_service_num.h"
|
||||||
#include "secure_service_dec.h"
|
#include "secure_service_dec.h"
|
||||||
|
|
||||||
typedef void (*secure_service_t)(void);
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Woverride-init"
|
#pragma GCC diagnostic ignored "-Woverride-init"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const DRAM_ATTR secure_service_t tee_secure_service_table[] = {
|
const DRAM_ATTR secure_service_entry_t tee_secure_service_table[] = {
|
||||||
[0 ... MAX_SECURE_SERVICES - 1] = (secure_service_t)NULL,
|
#define __SECURE_SERVICE(NR, SYM, ARGC) { .id = NR, .func = _ss_##SYM, .nargs = ARGC },
|
||||||
|
|
||||||
#define __SECURE_SERVICE(nr, symbol, nargs) [nr] = (secure_service_t)_ss_##symbol,
|
|
||||||
#include "secure_service.h"
|
#include "secure_service.h"
|
||||||
};
|
};
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
Reference in New Issue
Block a user