add stack protector safety when linking libc

* introduce zigrt file. it contains only weak symbols so that
   multiple instances can be merged. it contains __zig_panic
   so that multiple .o files can call the same panic function.
 * remove `@setFnVisible` builtin and add @setGlobalLinkage builtin
   which is more powerful
 * add `@panic` builtin function.
 * fix collision of symbols with extern prototypes and internal
   function names
 * add stack protector safety when linking against libc. To add
   the safety mechanism without libc requires implementing
   Thread Local Storage. See #276
master
Andrew Kelley 2017-03-26 21:07:07 -04:00
parent 8aeea72654
commit a32b5929cc
19 changed files with 437 additions and 185 deletions

View File

@ -233,8 +233,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_STD_DEST}/special")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}/special")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")
add_executable(run_tests ${TEST_SOURCES})

View File

@ -1,5 +1,5 @@
(setq zig
'(("\\b\\(@sizeOf\\|@alignOf\\|@maxValue\\|@minValue\\|@memberCount\\|@typeOf\\|@addWithOverflow\\|@subWithOverflow\\|@mulWithOverflow\\|@shlWithOverflow\\|@cInclude\\|@cDefine\\|@cUndef\\|@compileVar\\|@generatedCode\\|@ctz\\|@clz\\|@import\\|@cImport\\|@errorName\\|@typeName\\|@isInteger\\|@isFloat\\|@canImplicitCast\\|@embedFile\\|@cmpxchg\\|@fence\\|@divExact\\|@truncate\\|@compileError\\|@compileLog\\|@intType\\|@unreachable\\|@setFnTest\\|@setFnVisible\\|@setDebugSafety\\|@alloca\\|@setGlobalAlign\\|@setGlobalSection\\)" . font-lock-builtin-face)
'(("\\b\\(@sizeOf\\|@alignOf\\|@maxValue\\|@minValue\\|@memberCount\\|@typeOf\\|@addWithOverflow\\|@subWithOverflow\\|@mulWithOverflow\\|@shlWithOverflow\\|@cInclude\\|@cDefine\\|@cUndef\\|@compileVar\\|@generatedCode\\|@ctz\\|@clz\\|@import\\|@cImport\\|@errorName\\|@typeName\\|@isInteger\\|@isFloat\\|@canImplicitCast\\|@embedFile\\|@cmpxchg\\|@fence\\|@divExact\\|@truncate\\|@compileError\\|@compileLog\\|@intType\\|@unreachable\\|@setDebugSafety\\|@alloca\\|@setGlobalAlign\\|@setGlobalLinkage\\|@setGlobalSection\\)" . font-lock-builtin-face)
("\\b\\(fn\\|use\\|while\\|for\\|break\\|continue\\|goto\\|if\\|else\\|switch\\|try\\|return\\|defer\\|asm\\|unreachable\\|const\\|var\\|extern\\|packed\\|export\\|pub\\|noalias\\|inline\\|comptime\\|nakedcc\\|coldcc\\|volatile\\|struct\\|enum\\|union\\)\\b" . font-lock-keyword-face)

View File

@ -626,3 +626,10 @@ Sets the alignment property of a global variable.
### @setGlobalSection(global_variable_name, section_name: []u8) -> bool
Puts the global variable in the specified section.
### @panic(message: []const u8) -> noreturn
Invokes the panic handler function. By default the panic handler function
calls the public `panic` function exposed in the root source file, or
if there is not one specified, invokes the one provided in
`std/special/panic.zig`.

View File

@ -237,6 +237,13 @@ enum VisibMod {
VisibModExport,
};
enum GlobalLinkageId {
GlobalLinkageIdInternal,
GlobalLinkageIdStrong,
GlobalLinkageIdWeak,
GlobalLinkageIdLinkOnce,
};
enum TldId {
TldIdVar,
TldIdFn,
@ -273,6 +280,8 @@ struct TldVar {
uint64_t alignment;
AstNode *set_global_section_node;
Buf *section_name;
AstNode *set_global_linkage_node;
GlobalLinkageId linkage;
};
struct TldFn {
@ -1116,8 +1125,6 @@ struct FnTableEntry {
Buf symbol_name;
TypeTableEntry *type_entry; // function type
TypeTableEntry *implicit_return_type;
bool internal_linkage;
bool disable_export;
bool is_test;
FnInline fn_inline;
FnAnalState anal_state;
@ -1128,7 +1135,6 @@ struct FnTableEntry {
Buf **param_names;
AstNode *fn_no_inline_set_node;
AstNode *fn_export_set_node;
AstNode *fn_static_eval_set_node;
ZigList<IrInstruction *> alloca_list;
@ -1138,6 +1144,8 @@ struct FnTableEntry {
uint64_t alignment;
AstNode *set_global_section_node;
Buf *section_name;
AstNode *set_global_linkage_node;
GlobalLinkageId linkage;
};
uint32_t fn_table_entry_hash(FnTableEntry*);
@ -1178,7 +1186,6 @@ enum BuiltinFnId {
BuiltinFnIdDivExact,
BuiltinFnIdTruncate,
BuiltinFnIdIntType,
BuiltinFnIdSetFnVisible,
BuiltinFnIdSetDebugSafety,
BuiltinFnIdAlloca,
BuiltinFnIdTypeName,
@ -1187,6 +1194,8 @@ enum BuiltinFnId {
BuiltinFnIdCanImplicitCast,
BuiltinFnIdSetGlobalAlign,
BuiltinFnIdSetGlobalSection,
BuiltinFnIdSetGlobalLinkage,
BuiltinFnIdPanic,
};
struct BuiltinFnEntry {
@ -1300,7 +1309,8 @@ struct CodeGen {
HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> compile_vars;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_symbol_names;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
ZigList<ImportTableEntry *> import_queue;
size_t import_queue_index;
@ -1346,6 +1356,7 @@ struct CodeGen {
TypeTableEntry *entry_environ_enum;
TypeTableEntry *entry_oformat_enum;
TypeTableEntry *entry_atomic_order_enum;
TypeTableEntry *entry_global_linkage_enum;
TypeTableEntry *entry_arg_tuple;
} builtin_types;
@ -1378,7 +1389,7 @@ struct CodeGen {
bool is_native_target;
PackageTableEntry *root_package;
PackageTableEntry *std_package;
PackageTableEntry *panic_package;
PackageTableEntry *zigrt_package;
Buf *root_out_name;
bool windows_subsystem_windows;
bool windows_subsystem_console;
@ -1388,6 +1399,7 @@ struct CodeGen {
Buf *mios_version_min;
bool linker_rdynamic;
const char *linker_script;
bool omit_zigrt;
// The function definitions this module includes. There must be a corresponding
// fn_protos entry.
@ -1401,7 +1413,8 @@ struct CodeGen {
OutType out_type;
FnTableEntry *cur_fn;
FnTableEntry *main_fn;
FnTableEntry *panic_fn;
FnTableEntry *user_panic_fn;
FnTableEntry *extern_panic_fn;
LLVMValueRef cur_ret_ptr;
LLVMValueRef cur_fn_val;
ZigList<LLVMBasicBlockRef> break_block_stack;
@ -1656,7 +1669,6 @@ enum IrInstructionId {
IrInstructionIdTypeOf,
IrInstructionIdToPtrType,
IrInstructionIdPtrTypeChild,
IrInstructionIdSetFnVisible,
IrInstructionIdSetDebugSafety,
IrInstructionIdArrayType,
IrInstructionIdSliceType,
@ -1718,7 +1730,9 @@ enum IrInstructionId {
IrInstructionIdCanImplicitCast,
IrInstructionIdSetGlobalAlign,
IrInstructionIdSetGlobalSection,
IrInstructionIdSetGlobalLinkage,
IrInstructionIdDeclRef,
IrInstructionIdPanic,
};
struct IrInstruction {
@ -1999,13 +2013,6 @@ struct IrInstructionPtrTypeChild {
IrInstruction *value;
};
struct IrInstructionSetFnVisible {
IrInstruction base;
IrInstruction *fn_value;
IrInstruction *is_visible;
};
struct IrInstructionSetDebugSafety {
IrInstruction base;
@ -2439,6 +2446,13 @@ struct IrInstructionSetGlobalSection {
IrInstruction *value;
};
struct IrInstructionSetGlobalLinkage {
IrInstruction base;
Tld *tld;
IrInstruction *value;
};
struct IrInstructionDeclRef {
IrInstruction base;
@ -2446,6 +2460,12 @@ struct IrInstructionDeclRef {
LVal lval;
};
struct IrInstructionPanic {
IrInstruction base;
IrInstruction *msg;
};
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;

View File

@ -1762,7 +1762,7 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) {
buf_append_buf(buf, tld->name);
}
FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage) {
FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage) {
FnTableEntry *fn_entry = allocate<FnTableEntry>(1);
fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
@ -1770,7 +1770,7 @@ FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage) {
fn_entry->analyzed_executable.fn_entry = fn_entry;
fn_entry->ir_executable.fn_entry = fn_entry;
fn_entry->fn_inline = inline_value;
fn_entry->internal_linkage = internal_linkage;
fn_entry->linkage = linkage;
return fn_entry;
}
@ -1780,8 +1780,9 @@ FnTableEntry *create_fn(AstNode *proto_node) {
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto;
bool internal_linkage = (fn_proto->visib_mod != VisibModExport && !proto_node->data.fn_proto.is_extern);
FnTableEntry *fn_entry = create_fn_raw(inline_value, internal_linkage);
GlobalLinkageId linkage = (fn_proto->visib_mod == VisibModExport || proto_node->data.fn_proto.is_extern) ?
GlobalLinkageIdStrong : GlobalLinkageIdInternal;
FnTableEntry *fn_entry = create_fn_raw(inline_value, linkage);
fn_entry->proto_node = proto_node;
fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr :
@ -1807,12 +1808,10 @@ static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntr
buf_ptr(&fn_type->name)));
}
static void typecheck_panic_fn(CodeGen *g) {
assert(g->panic_fn);
AstNode *proto_node = g->panic_fn->proto_node;
static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
AstNode *proto_node = panic_fn->proto_node;
assert(proto_node->type == NodeTypeFnProto);
TypeTableEntry *fn_type = g->panic_fn->type_entry;
TypeTableEntry *fn_type = panic_fn->type_entry;
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
if (fn_type_id->param_count != 1) {
return wrong_panic_prototype(g, proto_node, fn_type);
@ -1862,6 +1861,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
add_node_error(g, param_node, buf_sprintf("missing parameter name"));
}
}
} else if (fn_table_entry->linkage != GlobalLinkageIdInternal) {
g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
}
Scope *child_scope = fn_table_entry->fndef_scope ? &fn_table_entry->fndef_scope->base : tld_fn->base.parent_scope;
@ -1892,18 +1893,16 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
}
}
} else if (buf_eql_str(&fn_table_entry->symbol_name, "panic")) {
g->panic_fn = fn_table_entry;
typecheck_panic_fn(g);
typecheck_panic_fn(g, fn_table_entry);
}
} else if (import->package == g->panic_package && scope_is_root_decls(tld_fn->base.parent_scope)) {
if (buf_eql_str(&fn_table_entry->symbol_name, "panic")) {
g->panic_fn = fn_table_entry;
typecheck_panic_fn(g);
} else if (import->package == g->zigrt_package && scope_is_root_decls(tld_fn->base.parent_scope)) {
if (buf_eql_str(&fn_table_entry->symbol_name, "__zig_panic")) {
g->extern_panic_fn = fn_table_entry;
}
}
}
} else if (source_node->type == NodeTypeTestDecl) {
FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, false);
FnTableEntry *fn_table_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong);
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');
@ -1931,16 +1930,12 @@ static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) {
}
static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
if (tld->visib_mod == VisibModExport ||
(buf_eql_str(tld->name, "panic") &&
(decls_scope->import->package == g->panic_package || decls_scope->import == g->root_import)) ||
(tld->id == TldIdVar && g->is_test_build))
{
if (tld->visib_mod == VisibModExport || (tld->id == TldIdVar && g->is_test_build)) {
g->resolve_queue.append(tld);
}
if (tld->visib_mod == VisibModExport) {
auto entry = g->external_symbol_names.put_unique(tld->name, tld);
auto entry = g->exported_symbol_names.put_unique(tld->name, tld);
if (entry) {
Tld *other_tld = entry->value;
ErrorMsg *msg = add_node_error(g, tld->source_node,
@ -2060,6 +2055,15 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
TldFn *tld_fn = allocate<TldFn>(1);
init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base);
add_top_level_decl(g, decls_scope, &tld_fn->base);
ImportTableEntry *import = get_scope_import(&decls_scope->base);
if (import == g->root_import && scope_is_root_decls(&decls_scope->base) &&
buf_eql_str(fn_name, "panic"))
{
g->compile_vars.put(buf_create_from_str("panic_implementation_provided"),
create_const_bool(g, true));
}
break;
}
case NodeTypeUse:
@ -4206,3 +4210,36 @@ ConstParent *get_const_val_parent(ConstExprValue *value) {
}
return nullptr;
}
FnTableEntry *get_extern_panic_fn(CodeGen *g) {
if (g->extern_panic_fn)
return g->extern_panic_fn;
FnTypeId fn_type_id = {0};
fn_type_id.is_extern = true;
fn_type_id.is_cold = true;
fn_type_id.param_count = 2;
fn_type_id.param_info = allocate<FnTypeParamInfo>(2);
fn_type_id.next_param_index = 0;
fn_type_id.param_info[0].type = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
fn_type_id.param_info[1].type = g->builtin_types.entry_usize;
fn_type_id.return_type = g->builtin_types.entry_unreachable;
TypeTableEntry *fn_type = get_fn_type(g, &fn_type_id);
assert(!type_is_invalid(fn_type));
FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong);
buf_init_from_str(&fn_entry->symbol_name, "__zig_panic");
TldFn *tld_fn = allocate<TldFn>(1);
init_tld(&tld_fn->base, TldIdFn, &fn_entry->symbol_name, VisibModPrivate, nullptr, nullptr);
tld_fn->fn_entry = fn_entry;
g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
fn_entry->type_entry = fn_type;
g->extern_panic_fn = fn_entry;
return g->extern_panic_fn;
}

View File

@ -72,7 +72,7 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent
bool is_const, ConstExprValue *init_value, Tld *src_tld);
TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
FnTableEntry *create_fn(AstNode *proto_node);
FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage);
FnTableEntry *create_fn_raw(FnInline inline_value, GlobalLinkageId linkage);
void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc);
AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index);
FnTableEntry *scope_get_fn_if_root(Scope *scope);
@ -148,5 +148,6 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val);
TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, size_t size_in_bits);
ConstParent *get_const_val_parent(ConstExprValue *value);
FnTableEntry *get_extern_panic_fn(CodeGen *g);
#endif

View File

@ -67,7 +67,8 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->llvm_fn_table.init(16);
g->memoized_fn_eval_table.init(16);
g->compile_vars.init(16);
g->external_symbol_names.init(8);
g->exported_symbol_names.init(8);
g->external_prototypes.init(8);
g->is_release_build = false;
g->is_test_build = false;
g->want_h_file = true;
@ -140,6 +141,10 @@ void codegen_set_is_release(CodeGen *g, bool is_release_build) {
g->is_release_build = is_release_build;
}
void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt) {
g->omit_zigrt = omit_zigrt;
}
void codegen_set_is_test(CodeGen *g, bool is_test_build) {
g->is_test_build = is_test_build;
}
@ -256,10 +261,22 @@ static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const c
LLVMAddAttributeAtIndex(val, attr_index, llvm_attr);
}
static void addLLVMAttrStr(LLVMValueRef val, LLVMAttributeIndex attr_index,
const char *attr_name, const char *attr_val)
{
LLVMAttributeRef llvm_attr = LLVMCreateStringAttribute(LLVMGetGlobalContext(),
attr_name, strlen(attr_name), attr_val, strlen(attr_val));
LLVMAddAttributeAtIndex(val, attr_index, llvm_attr);
}
static void addLLVMFnAttr(LLVMValueRef fn_val, const char *attr_name) {
return addLLVMAttr(fn_val, -1, attr_name);
}
static void addLLVMFnAttrStr(LLVMValueRef fn_val, const char *attr_name, const char *attr_val) {
return addLLVMAttrStr(fn_val, -1, attr_name, attr_val);
}
static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const char *attr_name) {
return addLLVMAttr(arg_val, param_index + 1, attr_name);
}
@ -271,15 +288,19 @@ static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, c
LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
}
static bool is_symbol_available(CodeGen *g, Buf *name) {
return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
}
static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) {
if (external_linkage || g->external_symbol_names.maybe_get(original_name) == nullptr) {
if (external_linkage || is_symbol_available(g, original_name)) {
return original_name;
}
int n = 0;
for (;; n += 1) {
Buf *new_name = buf_sprintf("%s.%d", buf_ptr(original_name), n);
if (g->external_symbol_names.maybe_get(new_name) == nullptr) {
if (is_symbol_available(g, new_name)) {
return new_name;
}
}
@ -289,11 +310,12 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, !fn_table_entry->internal_linkage);
bool external_linkage = (fn_table_entry->linkage != GlobalLinkageIdInternal);
Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, external_linkage);
TypeTableEntry *fn_type = fn_table_entry->type_entry;
LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
if (!fn_table_entry->internal_linkage && fn_table_entry->body_node == nullptr) {
if (external_linkage && fn_table_entry->body_node == nullptr) {
LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
if (existing_llvm_fn) {
fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
@ -318,12 +340,35 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
}
LLVMSetLinkage(fn_table_entry->llvm_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage);
switch (fn_table_entry->linkage) {
case GlobalLinkageIdInternal:
LLVMSetLinkage(fn_table_entry->llvm_value, LLVMInternalLinkage);
break;
case GlobalLinkageIdStrong:
LLVMSetLinkage(fn_table_entry->llvm_value, LLVMExternalLinkage);
break;
case GlobalLinkageIdWeak:
LLVMSetLinkage(fn_table_entry->llvm_value, LLVMWeakODRLinkage);
break;
case GlobalLinkageIdLinkOnce:
LLVMSetLinkage(fn_table_entry->llvm_value, LLVMLinkOnceODRLinkage);
break;
}
if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {
addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
}
if (fn_table_entry->body_node != nullptr) {
bool want_fn_safety = !g->is_release_build && !fn_table_entry->def_scope->safety_off;
if (want_fn_safety) {
if (g->link_libc) {
addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong");
addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4");
}
}
}
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention);
if (fn_type->data.fn.fn_type_id.is_cold) {
ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
@ -363,10 +408,11 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
bool is_definition = fn_table_entry->body_node != nullptr;
unsigned flags = 0;
bool is_optimized = g->is_release_build;
bool is_internal_linkage = (fn_table_entry->linkage == GlobalLinkageIdInternal);
ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",
import->di_file, line_number,
fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage,
fn_table_entry->type_entry->di_type, is_internal_linkage,
is_definition, scope_line, flags, is_optimized, nullptr);
scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
@ -544,13 +590,28 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
return val->llvm_global;
}
static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
LLVMValueRef msg_arg = get_panic_msg_ptr_val(g, msg_id);
ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, g->panic_fn->type_entry->data.fn.calling_convention, "");
static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {
FnTableEntry *panic_fn = get_extern_panic_fn(g);
LLVMValueRef fn_val = fn_llvm_value(g, panic_fn);
TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index;
size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index;
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, ptr_index, "");
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, msg_arg, len_index, "");
LLVMValueRef args[] = {
LLVMBuildLoad(g->builder, ptr_ptr, ""),
LLVMBuildLoad(g->builder, len_ptr, ""),
};
ZigLLVMBuildCall(g->builder, fn_val, args, 2, panic_fn->type_entry->data.fn.calling_convention, "");
LLVMBuildUnreachable(g->builder);
}
static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
gen_panic(g, get_panic_msg_ptr_val(g, msg_id));
}
static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
LLVMIntPredicate lower_pred, LLVMValueRef lower_value,
LLVMIntPredicate upper_pred, LLVMValueRef upper_value)
@ -2564,6 +2625,11 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
return tmp_array_ptr;
}
static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
gen_panic(g, ir_llvm_value(g, instruction->msg));
return nullptr;
}
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@ -2584,7 +2650,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdToPtrType:
case IrInstructionIdPtrTypeChild:
case IrInstructionIdFieldPtr:
case IrInstructionIdSetFnVisible:
case IrInstructionIdSetDebugSafety:
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
@ -2615,7 +2680,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdCanImplicitCast:
case IrInstructionIdSetGlobalAlign:
case IrInstructionIdSetGlobalSection:
case IrInstructionIdSetGlobalLinkage:
case IrInstructionIdDeclRef:
case IrInstructionIdSwitchVar:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@ -2721,8 +2788,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction);
case IrInstructionIdContainerInitList:
return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdSwitchVar:
zig_panic("TODO render switch var instruction to LLVM");
case IrInstructionIdPanic:
return ir_render_panic(g, executable, (IrInstructionPanic *)instruction);
}
zig_unreachable();
}
@ -3659,6 +3726,18 @@ static const CIntTypeInfo c_int_type_infos[] = {
static const bool is_signed_list[] = { false, true, };
struct GlobalLinkageValue {
GlobalLinkageId id;
const char *name;
};
static const GlobalLinkageValue global_linkage_values[] = {
{GlobalLinkageIdInternal, "Internal"},
{GlobalLinkageIdStrong, "Strong"},
{GlobalLinkageIdWeak, "Weak"},
{GlobalLinkageIdLinkOnce, "LinkOnce"},
};
static void define_builtin_types(CodeGen *g) {
{
// if this type is anywhere in the AST, we should never hit codegen.
@ -3995,6 +4074,30 @@ static void define_builtin_types(CodeGen *g) {
g->primitive_type_table.put(&entry->name, entry);
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "GlobalLinkage");
uint32_t field_count = array_length(global_linkage_values);
entry->data.enumeration.src_field_count = field_count;
entry->data.enumeration.fields = allocate<TypeEnumField>(field_count);
for (uint32_t i = 0; i < field_count; i += 1) {
TypeEnumField *type_enum_field = &entry->data.enumeration.fields[i];
const GlobalLinkageValue *value = &global_linkage_values[i];
type_enum_field->name = buf_create_from_str(value->name);
type_enum_field->value = i;
type_enum_field->type_entry = g->builtin_types.entry_void;
}
entry->data.enumeration.complete = true;
entry->data.enumeration.zero_bits_known = true;
TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
entry->data.enumeration.tag_type = tag_type_entry;
g->builtin_types.entry_global_linkage_enum = entry;
g->primitive_type_table.put(&entry->name, entry);
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
entry->zero_bits = true; // only allowed at compile time
@ -4145,11 +4248,12 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);
create_builtin_fn(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);
create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
create_builtin_fn(g, BuiltinFnIdPanic, "panic", 1);
}
static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) {
@ -4180,6 +4284,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
add_compile_var(g, "link_libs", const_val);
}
add_compile_var(g, "panic_implementation_provided", create_const_bool(g, false));
}
static void init(CodeGen *g, Buf *source_path) {
@ -4309,9 +4414,10 @@ static PackageTableEntry *create_bootstrap_pkg(CodeGen *g) {
return package;
}
static PackageTableEntry *create_panic_pkg(CodeGen *g) {
static PackageTableEntry *create_zigrt_pkg(CodeGen *g) {
PackageTableEntry *package = new_package(buf_ptr(g->zig_std_special_dir), "");
package->package_table.put(buf_create_from_str("std"), g->std_package);
package->package_table.put(buf_create_from_str("@root"), g->root_package);
return package;
}
@ -4337,9 +4443,9 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
if (!g->is_test_build && g->have_pub_main && (g->out_type == OutTypeObj || g->out_type == OutTypeExe)) {
g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig");
}
if (!g->have_pub_panic) {
g->panic_package = create_panic_pkg(g);
add_special_code(g, g->panic_package, "panic.zig");
if (!g->omit_zigrt) {
g->zigrt_package = create_zigrt_pkg(g);
add_special_code(g, g->zigrt_package, "zigrt.zig");
}
if (g->verbose) {
@ -4509,7 +4615,7 @@ void codegen_generate_h_file(CodeGen *g) {
for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
FnTableEntry *fn_table_entry = g->fn_defs.at(fn_def_i);
if (fn_table_entry->internal_linkage)
if (fn_table_entry->linkage == GlobalLinkageIdInternal)
continue;
FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;

View File

@ -43,6 +43,7 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);
void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);
void codegen_set_linker_script(CodeGen *g, const char *linker_script);
void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);
void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);

View File

@ -276,10 +276,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeChild *)
return IrInstructionIdPtrTypeChild;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnVisible *) {
return IrInstructionIdSetFnVisible;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety *) {
return IrInstructionIdSetDebugSafety;
}
@ -528,10 +524,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection
return IrInstructionIdSetGlobalSection;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalLinkage *) {
return IrInstructionIdSetGlobalLinkage;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) {
return IrInstructionIdDeclRef;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionPanic *) {
return IrInstructionIdPanic;
}
template<typename T>
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@ -1147,19 +1151,6 @@ static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstN
return &instruction->base;
}
static IrInstruction *ir_build_set_fn_visible(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn_value,
IrInstruction *is_visible)
{
IrInstructionSetFnVisible *instruction = ir_build_instruction<IrInstructionSetFnVisible>(irb, scope, source_node);
instruction->fn_value = fn_value;
instruction->is_visible = is_visible;
ir_ref_instruction(fn_value, irb->current_basic_block);
ir_ref_instruction(is_visible, irb->current_basic_block);
return &instruction->base;
}
static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *scope_value, IrInstruction *debug_safety_on)
{
@ -2092,6 +2083,19 @@ static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope,
return &instruction->base;
}
static IrInstruction *ir_build_set_global_linkage(IrBuilder *irb, Scope *scope, AstNode *source_node,
Tld *tld, IrInstruction *value)
{
IrInstructionSetGlobalLinkage *instruction = ir_build_instruction<IrInstructionSetGlobalLinkage>(
irb, scope, source_node);
instruction->tld = tld;
instruction->value = value;
ir_ref_instruction(value, irb->current_basic_block);
return &instruction->base;
}
static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
Tld *tld, LVal lval)
{
@ -2103,6 +2107,17 @@ static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *s
return &instruction->base;
}
static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *msg) {
IrInstructionPanic *instruction = ir_build_instruction<IrInstructionPanic>(irb, scope, source_node);
instruction->base.value.special = ConstValSpecialStatic;
instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
instruction->msg = msg;
ir_ref_instruction(msg, irb->current_basic_block);
return &instruction->base;
}
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
return nullptr;
}
@ -2287,14 +2302,6 @@ static IrInstruction *ir_instruction_ptrtypechild_get_dep(IrInstructionPtrTypeCh
}
}
static IrInstruction *ir_instruction_setfnvisible_get_dep(IrInstructionSetFnVisible *instruction, size_t index) {
switch (index) {
case 0: return instruction->fn_value;
case 1: return instruction->is_visible;
default: return nullptr;
}
}
static IrInstruction *ir_instruction_setdebugsafety_get_dep(IrInstructionSetDebugSafety *instruction, size_t index) {
switch (index) {
case 0: return instruction->scope_value;
@ -2742,10 +2749,24 @@ static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGl
}
}
static IrInstruction *ir_instruction_setgloballinkage_get_dep(IrInstructionSetGlobalLinkage *instruction, size_t index) {
switch (index) {
case 0: return instruction->value;
default: return nullptr;
}
}
static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) {
return nullptr;
}
static IrInstruction *ir_instruction_panic_get_dep(IrInstructionPanic *instruction, size_t index) {
switch (index) {
case 0: return instruction->msg;
default: return nullptr;
}
}
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@ -2804,8 +2825,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_toptrtype_get_dep((IrInstructionToPtrType *) instruction, index);
case IrInstructionIdPtrTypeChild:
return ir_instruction_ptrtypechild_get_dep((IrInstructionPtrTypeChild *) instruction, index);
case IrInstructionIdSetFnVisible:
return ir_instruction_setfnvisible_get_dep((IrInstructionSetFnVisible *) instruction, index);
case IrInstructionIdSetDebugSafety:
return ir_instruction_setdebugsafety_get_dep((IrInstructionSetDebugSafety *) instruction, index);
case IrInstructionIdArrayType:
@ -2928,8 +2947,12 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_setglobalalign_get_dep((IrInstructionSetGlobalAlign *) instruction, index);
case IrInstructionIdSetGlobalSection:
return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index);
case IrInstructionIdSetGlobalLinkage:
return ir_instruction_setgloballinkage_get_dep((IrInstructionSetGlobalLinkage *) instruction, index);
case IrInstructionIdDeclRef:
return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index);
case IrInstructionIdPanic:
return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index);
}
zig_unreachable();
}
@ -3759,20 +3782,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg;
return ir_build_typeof(irb, scope, node, arg);
}
case BuiltinFnIdSetFnVisible:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
return ir_build_set_fn_visible(irb, scope, node, arg0_value, arg1_value);
}
case BuiltinFnIdSetDebugSafety:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@ -4145,6 +4154,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
case BuiltinFnIdSetGlobalAlign:
case BuiltinFnIdSetGlobalSection:
case BuiltinFnIdSetGlobalLinkage:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
if (arg0_node->type != NodeTypeSymbol) {
@ -4170,10 +4180,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (builtin_fn->id == BuiltinFnIdSetGlobalAlign) {
return ir_build_set_global_align(irb, scope, node, tld, arg1_value);
} else {
} else if (builtin_fn->id == BuiltinFnIdSetGlobalSection) {
return ir_build_set_global_section(irb, scope, node, tld, arg1_value);
} else if (builtin_fn->id == BuiltinFnIdSetGlobalLinkage) {
return ir_build_set_global_linkage(irb, scope, node, tld, arg1_value);
} else {
zig_unreachable();
}
}
case BuiltinFnIdPanic:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
return ir_build_panic(irb, scope, node, arg0_value);
}
}
zig_unreachable();
}
@ -4624,6 +4647,10 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode
if (fn_entry)
return ir_build_const_fn(irb, scope, node, fn_entry);
while (scope->id != ScopeIdBlock && scope->id != ScopeIdDecls) {
scope = scope->parent;
}
if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
TypeTableEntry *container_type = decls_scope->container_type;
@ -7096,6 +7123,23 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
return true;
}
static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, GlobalLinkageId *out) {
if (type_is_invalid(value->value.type))
return false;
IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_linkage_enum);
if (type_is_invalid(casted_value->value.type))
return false;
ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
if (!const_val)
return false;
*out = (GlobalLinkageId)const_val->data.x_enum.tag;
return true;
}
static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
if (type_is_invalid(value->value.type))
return nullptr;
@ -9557,42 +9601,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_type;
}
static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira,
IrInstructionSetFnVisible *set_fn_visible_instruction)
{
IrInstruction *fn_value = set_fn_visible_instruction->fn_value->other;
IrInstruction *is_visible_value = set_fn_visible_instruction->is_visible->other;
FnTableEntry *fn_entry = ir_resolve_fn(ira, fn_value);
if (!fn_entry)
return ira->codegen->builtin_types.entry_invalid;
bool want_export;
if (!ir_resolve_bool(ira, is_visible_value, &want_export))
return ira->codegen->builtin_types.entry_invalid;
AstNode *source_node = set_fn_visible_instruction->base.source_node;
if (fn_entry->fn_export_set_node) {
ErrorMsg *msg = ir_add_error_node(ira, source_node,
buf_sprintf("function visibility set twice"));
add_error_note(ira->codegen, msg, fn_entry->fn_export_set_node, buf_sprintf("first set here"));
return ira->codegen->builtin_types.entry_invalid;
}
fn_entry->fn_export_set_node = source_node;
AstNodeFnProto *fn_proto = &fn_entry->proto_node->data.fn_proto;
if (fn_proto->visib_mod != VisibModExport) {
ErrorMsg *msg = ir_add_error_node(ira, source_node,
buf_sprintf("function must be marked export to set function visibility"));
add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("function declared here"));
return ira->codegen->builtin_types.entry_invalid;
}
fn_entry->internal_linkage = !want_export;
ir_build_const_from(ira, &set_fn_visible_instruction->base);
return ira->codegen->builtin_types.entry_void;
}
static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira,
IrInstructionSetGlobalAlign *instruction)
{
@ -9677,6 +9685,45 @@ static TypeTableEntry *ir_analyze_instruction_set_global_section(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_void;
}
static TypeTableEntry *ir_analyze_instruction_set_global_linkage(IrAnalyze *ira,
IrInstructionSetGlobalLinkage *instruction)
{
Tld *tld = instruction->tld;
IrInstruction *linkage_value = instruction->value->other;
GlobalLinkageId linkage_scalar;
if (!ir_resolve_global_linkage(ira, linkage_value, &linkage_scalar))
return ira->codegen->builtin_types.entry_invalid;
AstNode **set_global_linkage_node;
GlobalLinkageId *dest_linkage_ptr;
if (tld->id == TldIdVar) {
TldVar *tld_var = (TldVar *)tld;
set_global_linkage_node = &tld_var->set_global_linkage_node;
dest_linkage_ptr = &tld_var->linkage;
} else if (tld->id == TldIdFn) {
TldFn *tld_fn = (TldFn *)tld;
FnTableEntry *fn_entry = tld_fn->fn_entry;
set_global_linkage_node = &fn_entry->set_global_linkage_node;
dest_linkage_ptr = &fn_entry->linkage;
} else {
// error is caught in pass1 IR gen
zig_unreachable();
}
AstNode *source_node = instruction->base.source_node;
if (*set_global_linkage_node) {
ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("linkage set twice"));
add_error_note(ira->codegen, msg, *set_global_linkage_node, buf_sprintf("first set here"));
return ira->codegen->builtin_types.entry_invalid;
}
*set_global_linkage_node = source_node;
*dest_linkage_ptr = linkage_scalar;
ir_build_const_from(ira, &instruction->base);
return ira->codegen->builtin_types.entry_void;
}
static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
IrInstructionSetDebugSafety *set_debug_safety_instruction)
{
@ -12147,6 +12194,22 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_bool;
}
static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) {
IrInstruction *msg = instruction->msg->other;
if (type_is_invalid(msg->value.type))
return ira->codegen->builtin_types.entry_invalid;
TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
if (type_is_invalid(casted_msg->value.type))
return ira->codegen->builtin_types.entry_invalid;
IrInstruction *new_instruction = ir_build_panic(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, casted_msg);
ir_link_new_instruction(new_instruction, &instruction->base);
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
}
static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
IrInstructionDeclRef *instruction)
{
@ -12266,12 +12329,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction);
case IrInstructionIdPtrTypeChild:
return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction);
case IrInstructionIdSetFnVisible:
return ir_analyze_instruction_set_fn_visible(ira, (IrInstructionSetFnVisible *)instruction);
case IrInstructionIdSetGlobalAlign:
return ir_analyze_instruction_set_global_align(ira, (IrInstructionSetGlobalAlign *)instruction);
case IrInstructionIdSetGlobalSection:
return ir_analyze_instruction_set_global_section(ira, (IrInstructionSetGlobalSection *)instruction);
case IrInstructionIdSetGlobalLinkage:
return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction);
case IrInstructionIdSetDebugSafety:
return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction);
case IrInstructionIdSliceType:
@ -12384,6 +12447,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
case IrInstructionIdDeclRef:
return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
case IrInstructionIdPanic:
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
case IrInstructionIdMaybeWrap:
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
@ -12482,7 +12547,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCall:
case IrInstructionIdReturn:
case IrInstructionIdUnreachable:
case IrInstructionIdSetFnVisible:
case IrInstructionIdSetDebugSafety:
case IrInstructionIdImport:
case IrInstructionIdCompileErr:
@ -12500,6 +12564,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCheckSwitchProngs:
case IrInstructionIdSetGlobalAlign:
case IrInstructionIdSetGlobalSection:
case IrInstructionIdSetGlobalLinkage:
case IrInstructionIdPanic:
return true;
case IrInstructionIdPhi:
case IrInstructionIdUnOp:
@ -12580,7 +12646,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
}
FnTableEntry *ir_create_inline_fn(CodeGen *codegen, Buf *fn_name, VariableTableEntry *var, Scope *parent_scope) {
FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, true);
FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdInternal);
buf_init_from_buf(&fn_entry->symbol_name, fn_name);
fn_entry->fndef_scope = create_fndef_scope(nullptr, parent_scope, fn_entry);

View File

@ -339,14 +339,6 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins
fprintf(irp->f, ")");
}
static void ir_print_set_fn_visible(IrPrint *irp, IrInstructionSetFnVisible *instruction) {
fprintf(irp->f, "@setFnVisible(");
ir_print_other_instruction(irp, instruction->fn_value);
fprintf(irp->f, ", ");
ir_print_other_instruction(irp, instruction->is_visible);
fprintf(irp->f, ")");
}
static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {
fprintf(irp->f, "@setDebugSafety(");
ir_print_other_instruction(irp, instruction->scope_value);
@ -849,6 +841,13 @@ static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSect
fprintf(irp->f, ")");
}
static void ir_print_set_global_linkage(IrPrint *irp, IrInstructionSetGlobalLinkage *instruction) {
fprintf(irp->f, "@setGlobalLinkage(%s,", buf_ptr(instruction->tld->name));
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, ")");
}
static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
const char *ptr_str = instruction->lval.is_ptr ? "ptr " : "";
const char *const_str = instruction->lval.is_const ? "const " : "";
@ -856,6 +855,13 @@ static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
fprintf(irp->f, "declref %s%s%s%s", const_str, volatile_str, ptr_str, buf_ptr(instruction->tld->name));
}
static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) {
fprintf(irp->f, "@panic(");
ir_print_other_instruction(irp, instruction->msg);
fprintf(irp->f, ")");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@ -933,9 +939,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdEnumFieldPtr:
ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
break;
case IrInstructionIdSetFnVisible:
ir_print_set_fn_visible(irp, (IrInstructionSetFnVisible *)instruction);
break;
case IrInstructionIdSetDebugSafety:
ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
break;
@ -1128,9 +1131,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSetGlobalSection:
ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction);
break;
case IrInstructionIdSetGlobalLinkage:
ir_print_set_global_linkage(irp, (IrInstructionSetGlobalLinkage *)instruction);
break;
case IrInstructionIdDeclRef:
ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction);
break;
case IrInstructionIdPanic:
ir_print_panic(irp, (IrInstructionPanic *)instruction);
break;
}
fprintf(irp->f, "\n");
}

View File

@ -52,6 +52,7 @@ static Buf *build_o(CodeGen *parent_gen, const char *oname) {
child_gen->link_libs.items[i] = parent_gen->link_libs.items[i];
}
codegen_set_omit_zigrt(child_gen, true);
child_gen->want_h_file = false;
codegen_set_is_release(child_gen, parent_gen->is_release_build);

View File

@ -635,8 +635,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
}
assert(fn_type->id == TypeTableEntryIdFn);
bool internal_linkage = false;
FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, internal_linkage);
FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, GlobalLinkageIdStrong);
buf_init_from_buf(&fn_entry->symbol_name, fn_name);
fn_entry->type_entry = fn_type;

View File

@ -13,7 +13,7 @@ var argc: usize = undefined;
var argv: &&u8 = undefined;
export nakedcc fn _start() -> noreturn {
@setFnVisible(this, want_start_symbol);
@setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
if (!want_start_symbol) {
unreachable;
}
@ -47,7 +47,7 @@ fn callMainAndExit() -> noreturn {
}
export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
@setFnVisible(this, want_main_symbol);
@setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
if (!want_main_symbol) {
unreachable;
}

View File

@ -30,7 +30,6 @@ export fn memcpy(noalias dest: ?&u8, noalias src: ?&const u8, n: usize) {
d[index] = s[index];
}
// Avoid dragging in the debug safety mechanisms into this .o file.
pub fn panic(message: []const u8) -> noreturn {
unreachable;
export fn __stack_chk_fail() {
@panic("stack smashing detected");
}

View File

@ -1,13 +1,3 @@
// Avoid dragging in the debug safety mechanisms into this .o file,
// unless we're trying to test this file.
pub fn panic(message: []const u8) -> noreturn {
if (@compileVar("is_test")) {
@import("std").debug.panic(message);
} else {
unreachable;
}
}
const CHAR_BIT = 8;
const du_int = u64;
const di_int = i64;
@ -262,7 +252,7 @@ export nakedcc fn __aeabi_uidivmod() {
unreachable;
}
@setFnVisible(this, false);
@setGlobalLinkage(__aeabi_uidivmod, GlobalLinkage.Internal);
}
export fn __udivmodsi4(a: su_int, b: su_int, rem: &su_int) -> su_int {

View File

@ -1,12 +0,0 @@
// This file is included if and only if the user's main source file does not
// include a public panic function.
// If this file wants to import other files *by name*, support for that would
// have to be added in the compiler.
pub coldcc fn panic(message: []const u8) -> noreturn {
if (@compileVar("os") == Os.freestanding) {
while (true) {}
} else {
@import("std").debug.panic(message);
}
}

16
std/special/zigrt.zig Normal file
View File

@ -0,0 +1,16 @@
// This file contains functions that zig depends on to coordinate between
// multiple .o files. The symbols are defined LinkOnce so that multiple
// instances of zig_rt.zig do not conflict with each other.
export coldcc fn __zig_panic(message_ptr: &const u8, message_len: usize) -> noreturn {
@setGlobalLinkage(__zig_panic, GlobalLinkage.Weak);
@setDebugSafety(this, false);
if (@compileVar("panic_implementation_provided")) {
@import("@root").panic(message_ptr[0...message_len]);
} else if (@compileVar("os") == Os.freestanding) {
while (true) {}
} else {
@import("std").debug.panic(message_ptr[0...message_len]);
}
}

View File

@ -12,7 +12,7 @@ test "emptyFunctionWithComments" {
}
export fn disabledExternFn() {
@setFnVisible(this, false);
@setGlobalLinkage(disabledExternFn, GlobalLinkage.Internal);
}
test "callDisabledExternFn" {

View File

@ -1828,6 +1828,18 @@ export fn entry() {
//////////////////////////////////////////////////////////////////////////////
static void add_debug_safety_test_cases(void) {
add_debug_safety_case("calling panic", R"SOURCE(
pub fn panic(message: []const u8) -> noreturn {
@breakpoint();
while (true) {}
}
pub fn main(args: [][]u8) -> %void {
if (!@compileVar("is_release")) {
@panic("oh no");
}
}
)SOURCE");
add_debug_safety_case("out of bounds slice access", R"SOURCE(
pub fn panic(message: []const u8) -> noreturn {
@breakpoint();