Prevent Mach-O from removing @init and @dynamic in a more reliable way #1200.

This commit is contained in:
Christoffer Lerno
2024-06-15 15:58:12 +02:00
parent c94610f8a9
commit b0b885d506
4 changed files with 49 additions and 22 deletions

View File

@@ -6,11 +6,11 @@
### Fixes
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
- Prevent Mach-O from removing `@init` and `@dynamic` in a more reliable way #1200.
### Stdlib changes
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.
## 0.6.0 Change list
### Changes / improvements

View File

@@ -135,10 +135,27 @@ LLVMValueRef llvm_get_selector(GenContext *c, const char *name)
}
void llvm_emit_macho_xtor(GenContext *c, LLVMValueRef *list, const char *name)
static LLVMValueRef llvm_emit_macho_xtor_use(GenContext *c, LLVMValueRef global, const char *name)
{
LLVMValueRef initializer = LLVMAddFunction(c->module, name, c->xtor_func_type);
LLVMSetLinkage(initializer, LLVMInternalLinkage);
LLVMSetAlignment(initializer, 8);
LLVMValueRef vals_fn[3] = { llvm_const_int(c, type_int, 1), initializer, llvm_get_zero(c, type_voidptr) };
LLVMValueRef result = LLVMConstNamedStruct(c->xtor_entry_type, vals_fn, 3);
LLVMBasicBlockRef last_block;
LLVMBuilderRef builder = llvm_create_function_entry(c, initializer, &last_block);
LLVMValueRef load = LLVMBuildLoad2(builder, LLVMTypeOf(LLVMGetInitializer(global)), global, ".retain_global");
LLVMSetVolatile(load, true);
LLVMBuildRetVoid(builder);
LLVMDisposeBuilder(builder);
return result;
}
static LLVMValueRef llvm_emit_macho_xtor(GenContext *c, LLVMValueRef *list, const char *name, const char *retain_name)
{
unsigned len = vec_size(list);
if (!len) return;
if (!len) return NULL;
scratch_buffer_clear();
scratch_buffer_append(".list$");
scratch_buffer_append(name);
@@ -151,31 +168,46 @@ void llvm_emit_macho_xtor(GenContext *c, LLVMValueRef *list, const char *name)
LLVMSetInitializer(global, array);
LLVMSetSection(global, scratch_buffer_to_string());
LLVMSetAlignment(global, llvm_abi_alignment(c, c->xtor_entry_type));
return llvm_emit_macho_xtor_use(c, global, retain_name);
}
void llvm_emit_constructors_and_destructors(GenContext *c)
{
if (platform_target.object_format == OBJ_FORMAT_MACHO)
{
llvm_emit_macho_xtor(c, c->constructors, "c3ctor");
llvm_emit_macho_xtor(c, c->destructors, "c3dtor");
LLVMValueRef c3_dynamic = LLVMGetNamedGlobal(c->module, "$c3_dynamic");
LLVMValueRef dtor_global = llvm_emit_macho_xtor(c, c->constructors, "c3ctor", ".c3_ctor_retain");
LLVMValueRef ctor_global = llvm_emit_macho_xtor(c, c->destructors, "c3dtor", ".c3_dtor_retain");
LLVMValueRef runtime_start = LLVMGetNamedFunction(c->module, "__c3_runtime_startup");
if (!runtime_start || !LLVMGetFirstBasicBlock(runtime_start)) return;
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, 65535), runtime_start, llvm_get_zero(c, type_voidptr) };
LLVMValueRef entry = LLVMConstNamedStruct(c->xtor_entry_type, vals, 3);
LLVMValueRef array = LLVMConstArray(c->xtor_entry_type, &entry, 1);
LLVMValueRef global_ctor = LLVMAddGlobal(c->module, LLVMTypeOf(array), "llvm.global_ctors");
LLVMSetLinkage(global_ctor, LLVMAppendingLinkage);
LLVMSetInitializer(global_ctor, array);
int len = 0;
LLVMValueRef ctors[5];
if (ctor_global) ctors[len++] = ctor_global;
if (dtor_global) ctors[len++] = dtor_global;
if (c3_dynamic) ctors[len++] = llvm_emit_macho_xtor_use(c, c3_dynamic, ".c3_dynamic_retain");
if (!runtime_start || !LLVMGetFirstBasicBlock(runtime_start))
{
goto EMIT_CTORS;
}
LLVMValueRef runtime_end = LLVMGetNamedFunction(c->module, "__c3_runtime_finalize");
if (!runtime_end || !LLVMGetFirstBasicBlock(runtime_end)) error_exit("Failed to find __c3_runtime_finalize in the same module as __c3_runtime_startup.");
vals[1] = runtime_end;
entry = LLVMConstNamedStruct(c->xtor_entry_type, vals, 3);
array = LLVMConstArray(c->xtor_entry_type, &entry, 1);
LLVMValueRef vals[3] = { llvm_const_int(c, type_int, 65535), runtime_end, llvm_get_zero(c, type_voidptr) };
LLVMValueRef entry = LLVMConstNamedStruct(c->xtor_entry_type, vals, 3);
LLVMValueRef array = LLVMConstArray(c->xtor_entry_type, &entry, 1);
LLVMValueRef global_dtor = LLVMAddGlobal(c->module, LLVMTypeOf(array), "llvm.global_dtors");
LLVMSetLinkage(global_dtor, LLVMAppendingLinkage);
LLVMSetInitializer(global_dtor, array);
vals[1] = runtime_start;
entry = LLVMConstNamedStruct(c->xtor_entry_type, vals, 3);
ctors[len++] = entry;
EMIT_CTORS:
if (len == 0) return;
array = LLVMConstArray(c->xtor_entry_type, ctors, len);
LLVMValueRef global_ctor = LLVMAddGlobal(c->module, LLVMTypeOf(array), "llvm.global_ctors");
LLVMSetLinkage(global_ctor, LLVMAppendingLinkage);
LLVMSetInitializer(global_ctor, array);
return;
}
llvm_emit_xtor(c, c->constructors, "llvm.global_ctors");

View File

@@ -562,11 +562,6 @@ void llvm_emit_dynamic_functions(GenContext *c, Decl **funcs)
LLVMSetInitializer(global, array);
LLVMSetSection(global, "__DATA,__c3_dynamic");
LLVMSetAlignment(global, llvm_abi_alignment(c, c->xtor_entry_type));
LLVMValueRef array_used = LLVMConstArray(LLVMTypeOf(global), &global, 1);
LLVMValueRef global_used = LLVMAddGlobal(c->module, LLVMTypeOf(array_used), "llvm.used");
LLVMSetLinkage(global_used, LLVMAppendingLinkage);
LLVMSetInitializer(global_used, array_used);
LLVMSetSection(global_used, "llvm.metadata");
return;
}

View File

@@ -32,7 +32,7 @@ fn void! delete_contains_index()
assert(test.contains(3));
test[0] = 10;
assert(test.contains(10));
test.remove_all_matches(10);
test.remove_item(10);
assert(test.array_view() == int[]{ 2, 3 });
assert(!test.contains(1));
assert(test.contains(2));
@@ -42,7 +42,7 @@ fn void! delete_contains_index()
assert(test.array_view() == int[]{ 0, 2, 3, 0 });
assert(test.index_of(0)! == 0);
assert(test.rindex_of(0)! == 3);
test.remove_all_matches(0);
test.remove_item(0);
assert(test.len() == 2);
assert(test.array_view() == int[]{ 2, 3 });
}