Skip to content

Commit

Permalink
rewriter: Redeclare static functions that have their address taken wi…
Browse files Browse the repository at this point in the history
…th __used__

When we make call gates for static functions that have their address taken, the
static function is only referenced from the asm for the call gate. When
compiling with optimizations dead code elimination may get rid of the static
functions unless they are marked with __attribute__((__used__)). The rewriter
previously prepended this attribute in this case to avoid that. This commit
removes the prepended attribute and instead redeclares these functions with that
attribute. Closes #414 and fixes a test added for #428.
  • Loading branch information
ayrtonm committed Oct 11, 2024
1 parent 504ba14 commit bcdef07
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 19 deletions.
4 changes: 3 additions & 1 deletion runtime/libia2/include/ia2.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
#define IA2_CALL(opaque, id) opaque
#define IA2_CAST(func, ty) (ty) (void *) func
#else
#define IA2_DEFINE_WRAPPER(func) IA2_DEFINE_WRAPPER_##func
#define IA2_DEFINE_WRAPPER(func) \
typeof(func) func __attribute__((__used__)); \
IA2_DEFINE_WRAPPER_##func
#define IA2_SIGHANDLER(func) ia2_sighandler_##func
/// Create a wrapped signal handler for `sa_sigaction`
///
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ add_subdirectory(shared_data)
add_subdirectory(global_fn_ptr)
add_subdirectory(rewrite_macros)
add_subdirectory(sighandler)
add_subdirectory(static_addr_taken)

# The following tests are not supported on ARM64 yet
if (NOT LIBIA2_AARCH64)
Expand Down
13 changes: 13 additions & 0 deletions tests/static_addr_taken/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
define_shared_lib(
SRCS lib.c
PKEY 2
)

define_test(
SRCS main.c
NEEDS_LD_WRAP
PKEY 1
CRITERION_TEST
)

define_ia2_wrapper()
10 changes: 10 additions & 0 deletions tests/static_addr_taken/include/static_fns.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

typedef void (*fn_ptr_ty)(void);

static void inline_noop(void) {
printf("called %s defined in header\n", __func__);
}

fn_ptr_ty *get_ptrs_in_main(void);
fn_ptr_ty *get_ptrs_in_lib(void);
40 changes: 40 additions & 0 deletions tests/static_addr_taken/lib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <criterion/criterion.h>
#include <criterion/logging.h>
#include <ia2.h>

#include <test_fault_handler.h>

#define IA2_COMPARTMENT 2
#include <ia2_compartment_init.inc>

#include "static_fns.h"

static void duplicate_noop(void) {
printf("called %s in library\n", __func__);
}

static void identical_name(void) {
static int x = 4;
printf("%s in library read x = %d\n", __func__, x);
}

static fn_ptr_ty ptrs[3] IA2_SHARED_DATA = {
inline_noop, duplicate_noop, identical_name
};

fn_ptr_ty *get_ptrs_in_lib(void) {
return ptrs;
}

Test(static_addr_taken, call_ptrs_in_lib) {
for (int i = 0; i < 3; i++) {
ptrs[i]();
}
}

Test(static_addr_taken, call_ptr_from_main) {
fn_ptr_ty *main_ptrs = get_ptrs_in_main();
for (int i = 0; i < 3; i++) {
main_ptrs[i]();
}
}
42 changes: 42 additions & 0 deletions tests/static_addr_taken/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <criterion/criterion.h>
#include <criterion/logging.h>
#include <ia2.h>

#define IA2_DEFINE_TEST_HANDLER
#include <test_fault_handler.h>

INIT_RUNTIME(2);
#define IA2_COMPARTMENT 1
#include <ia2_compartment_init.inc>

#include "static_fns.h"

static void duplicate_noop(void) {
printf("called %s in main binary\n", __func__);
}

static void identical_name(void) {
static int x = 3;
printf("%s in main binary read x = %d\n", __func__, x);
}

static fn_ptr_ty ptrs[3] IA2_SHARED_DATA = {
inline_noop, duplicate_noop, identical_name
};

fn_ptr_ty *get_ptrs_in_main(void) {
return ptrs;
}

Test(static_addr_taken, call_ptrs_in_main) {
for (int i = 0; i < 3; i++) {
ptrs[i]();
}
}

Test(static_addr_taken, call_ptr_from_lib) {
fn_ptr_ty *lib_ptrs = get_ptrs_in_lib();
for (int i = 0; i < 3; i++) {
lib_ptrs[i]();
}
}
19 changes: 1 addition & 18 deletions tools/rewriter/SourceRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,24 +666,6 @@ class FnPtrExpr : public RefactoringCallback {

auto [it, new_fn] = internal_addr_taken_fns[filename].insert(
std::make_pair(fn_name, new_type));

// TODO: Note that this only checks if a function is added to the
// internal_addr_taken_fns map. To make the rewriter idempotent we should
// check for an existing used attribute.
if (new_fn) {
auto decl_start = fn_decl->getBeginLoc();
if (!decl_start.isFileID()) {
llvm::errs() << "Error: non-file loc for function " << fn_name << '\n';
} else {
Replacement old_used_attr(sm, decl_start, 0,
llvm::StringRef("__attribute__((used)) "));
Replacement used_attr = replace_new_file(filename, old_used_attr);
auto err = file_replacements[filename].add(used_attr);
if (err) {
llvm::errs() << "Error adding replacements: " << err << '\n';
}
}
}
}

// This check must come after modifying the maps in this pass but before the
Expand All @@ -701,6 +683,7 @@ class FnPtrExpr : public RefactoringCallback {
return;
}

// Add the IA2_FN annotation around the function pointer expression
clang::CharSourceRange expansion_range = sm.getExpansionRange(loc);
Replacement old_r{sm, expansion_range, new_expr};
Replacement r = replace_new_file(filename, old_r);
Expand Down

0 comments on commit bcdef07

Please sign in to comment.