diff --git a/doc/langref.md b/doc/langref.md index 5d06719e75..a963490498 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -31,7 +31,7 @@ ExternDecl = "extern" (FnProto | VariableDeclaration) ";" FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr) -Directive = "#" "Symbol" "(" "String" ")" +Directive = "#" "Symbol" "(" Expression ")" VisibleMod = "pub" | "export" diff --git a/src/all_types.hpp b/src/all_types.hpp index 172e553b48..3b7c02d3ec 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -427,7 +427,7 @@ struct AstNodeFieldAccessExpr { struct AstNodeDirective { Buf name; - Buf param; + AstNode *expr; }; struct AstNodeRootExportDecl { @@ -526,6 +526,7 @@ struct AstNodeSwitchExpr { // populated by semantic analyzer Expr resolved_expr; + int const_chosen_prong_index; }; struct AstNodeSwitchProng { diff --git a/src/analyze.cpp b/src/analyze.cpp index eddda4ed18..f075740c44 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -816,6 +816,53 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor return get_fn_type(g, &fn_type_id); } +static Buf *resolve_const_expr_str(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode **node) { + TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); + TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *node); + + if (resolved_type->id == TypeTableEntryIdInvalid) { + return nullptr; + } + + ConstExprValue *const_str_val = &get_resolved_expr(*node)->const_val; + + if (!const_str_val->ok) { + add_node_error(g, *node, buf_sprintf("unable to resolve constant expression")); + return nullptr; + } + + ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0]; + uint64_t len = ptr_field->data.x_ptr.len; + Buf *result = buf_alloc(); + for (uint64_t i = 0; i < len; i += 1) { + ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i]; + uint64_t big_c = char_val->data.x_bignum.data.x_uint; + assert(big_c <= UINT8_MAX); + uint8_t c = big_c; + buf_append_char(result, c); + } + return result; +} + +static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockContext *context, + AstNode **node, bool *value) +{ + TypeTableEntry *resolved_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *node); + + if (resolved_type->id == TypeTableEntryIdInvalid) { + return false; + } + + ConstExprValue *const_bool_val = &get_resolved_expr(*node)->const_val; + + if (!const_bool_val->ok) { + add_node_error(g, *node, buf_sprintf("unable to resolve constant expression")); + return false; + } + + *value = const_bool_val->data.x_bool; + return true; +} static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, ImportTableEntry *import) @@ -839,23 +886,38 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t Buf *name = &directive_node->data.directive.name; if (buf_eql_str(name, "attribute")) { - Buf *attr_name = &directive_node->data.directive.param; if (fn_table_entry->fn_def_node) { - if (buf_eql_str(attr_name, "naked")) { - is_naked = true; - } else if (buf_eql_str(attr_name, "cold")) { - is_cold = true; - } else if (buf_eql_str(attr_name, "test")) { - is_test = true; - g->test_fn_count += 1; - } else { - add_node_error(g, directive_node, - buf_sprintf("invalid function attribute: '%s'", buf_ptr(name))); + Buf *attr_name = resolve_const_expr_str(g, import, import->block_context, + &directive_node->data.directive.expr); + if (attr_name) { + if (buf_eql_str(attr_name, "naked")) { + is_naked = true; + } else if (buf_eql_str(attr_name, "cold")) { + is_cold = true; + } else if (buf_eql_str(attr_name, "test")) { + is_test = true; + g->test_fn_count += 1; + } else { + add_node_error(g, directive_node, + buf_sprintf("invalid function attribute: '%s'", buf_ptr(name))); + } } } else { add_node_error(g, directive_node, buf_sprintf("invalid function attribute: '%s'", buf_ptr(name))); } + } else if (buf_eql_str(name, "condition")) { + if (fn_proto->visib_mod == VisibModExport) { + bool include; + bool ok = resolve_const_expr_bool(g, import, import->block_context, + &directive_node->data.directive.expr, &include); + if (ok && !include) { + fn_proto->visib_mod = VisibModPub; + } + } else { + add_node_error(g, directive_node, + buf_sprintf("#condition valid only on exported symbols")); + } } else { add_node_error(g, directive_node, buf_sprintf("invalid directive: '%s'", buf_ptr(name))); @@ -863,6 +925,15 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t } } + bool is_internal = (fn_proto->visib_mod != VisibModExport); + bool is_c_compat = !is_internal || fn_proto->is_extern; + fn_table_entry->internal_linkage = !is_c_compat; + if (!is_internal) { + fn_table_entry->ref_count += 1; + } + + + TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node, is_naked, is_cold); @@ -1242,8 +1313,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, auto entry = fn_table->maybe_get(proto_name); bool skip = false; - bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport); - bool is_c_compat = !is_internal || is_extern; bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate); if (entry) { add_node_error(g, proto_node, @@ -1263,10 +1332,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, fn_table_entry->import_entry = import; fn_table_entry->proto_node = proto_node; fn_table_entry->fn_def_node = fn_def_node; - fn_table_entry->internal_linkage = !is_c_compat; fn_table_entry->is_extern = is_extern; fn_table_entry->member_of_struct = struct_type; - fn_table_entry->ref_count = (proto_node->data.fn_proto.visib_mod == VisibModExport) ? 1 : 0; if (struct_type) { buf_resize(&fn_table_entry->symbol_name, 0); @@ -1290,7 +1357,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, g->main_fn = fn_table_entry; if (g->bootstrap_import && !g->is_test_build) { - g->bootstrap_import->fn_table.put(proto_name, fn_table_entry); + g->bootstrap_import->fn_table.put(buf_create_from_str("zig_user_main"), fn_table_entry); } } bool is_test_main_fn = !struct_type && (import == g->test_runner_import) && buf_eql_str(proto_name, "main"); @@ -4246,54 +4313,33 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry { AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field; - TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); - TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node); - - if (resolved_type->id == TypeTableEntryIdInvalid) { - return resolved_type; - } - - ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val; - - if (!const_str_val->ok) { - add_node_error(g, *str_node, buf_sprintf("@compile_var requires constant expression")); - return g->builtin_types.entry_void; - } - - ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0]; - uint64_t len = ptr_field->data.x_ptr.len; - Buf var_name = BUF_INIT; - buf_resize(&var_name, 0); - for (uint64_t i = 0; i < len; i += 1) { - ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i]; - uint64_t big_c = char_val->data.x_bignum.data.x_uint; - assert(big_c <= UINT8_MAX); - uint8_t c = big_c; - buf_append_char(&var_name, c); + Buf *var_name = resolve_const_expr_str(g, import, context, str_node); + if (!var_name) { + return g->builtin_types.entry_invalid; } ConstExprValue *const_val = &get_resolved_expr(node)->const_val; const_val->ok = true; const_val->depends_on_compile_var = true; - if (buf_eql_str(&var_name, "is_big_endian")) { + if (buf_eql_str(var_name, "is_big_endian")) { return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true); - } else if (buf_eql_str(&var_name, "is_release")) { + } else if (buf_eql_str(var_name, "is_release")) { return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true); - } else if (buf_eql_str(&var_name, "is_test")) { + } else if (buf_eql_str(var_name, "is_test")) { return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true); - } else if (buf_eql_str(&var_name, "os")) { + } else if (buf_eql_str(var_name, "os")) { const_val->data.x_enum.tag = g->target_os_index; return g->builtin_types.entry_os_enum; - } else if (buf_eql_str(&var_name, "arch")) { + } else if (buf_eql_str(var_name, "arch")) { const_val->data.x_enum.tag = g->target_arch_index; return g->builtin_types.entry_arch_enum; - } else if (buf_eql_str(&var_name, "environ")) { + } else if (buf_eql_str(var_name, "environ")) { const_val->data.x_enum.tag = g->target_environ_index; return g->builtin_types.entry_environ_enum; } else { add_node_error(g, *str_node, - buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name))); + buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name))); return g->builtin_types.entry_invalid; } } @@ -4740,7 +4786,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, field_use_counts = allocate(expr_type->data.enumeration.field_count); } - int const_chosen_prong_index = -1; + int *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index; + *const_chosen_prong_index = -1; AstNode *else_prong = nullptr; for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); @@ -4756,8 +4803,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, } var_type = expr_type; var_is_target_expr = true; - if (const_chosen_prong_index == -1) { - const_chosen_prong_index = prong_i; + if (*const_chosen_prong_index == -1 && expr_val->ok) { + *const_chosen_prong_index = prong_i; } } else { bool all_agree_on_var_type = true; @@ -4792,7 +4839,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, } if (!any_errors && expr_val->ok) { if (expr_val->data.x_enum.tag == type_enum_field->value) { - const_chosen_prong_index = prong_i; + *const_chosen_prong_index = prong_i; } } } else { @@ -4844,7 +4891,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); BlockContext *child_context = prong_node->data.switch_prong.block_context; - child_context->codegen_excluded = expr_val->ok && (const_chosen_prong_index != prong_i); + child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i); peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type, prong_node->data.switch_prong.expr); @@ -4872,10 +4919,9 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, } if (expr_val->ok) { - assert(const_chosen_prong_index != -1); + assert(*const_chosen_prong_index != -1); - *const_val = get_resolved_expr(peer_nodes[const_chosen_prong_index])->const_val; - const_val->ok = true; + *const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val; // the target expr depends on a compile var, // so the entire if statement does too const_val->depends_on_compile_var = true; @@ -5490,6 +5536,12 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode AstNode *param = node->data.fn_proto.params.at(i); collect_expr_decl_deps(g, import, param, decl_node); } + if (node->data.fn_proto.directives) { + for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) { + AstNode *directive = node->data.fn_proto.directives->at(i); + collect_expr_decl_deps(g, import, directive, decl_node); + } + } collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node); break; case NodeTypeParamDecl: @@ -5498,12 +5550,14 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode case NodeTypeTypeDecl: collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node); break; + case NodeTypeDirective: + collect_expr_decl_deps(g, import, node->data.directive.expr, decl_node); + break; case NodeTypeVariableDeclaration: case NodeTypeRootExportDecl: case NodeTypeFnDef: case NodeTypeRoot: case NodeTypeFnDecl: - case NodeTypeDirective: case NodeTypeImport: case NodeTypeCImport: case NodeTypeLabel: diff --git a/src/ast_render.cpp b/src/ast_render.cpp index a302652eb1..118eee8f2c 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -339,6 +339,7 @@ void ast_print(FILE *f, AstNode *node, int indent) { break; case NodeTypeDirective: fprintf(f, "%s\n", node_type_str(node->type)); + ast_print(f, node->data.directive.expr, indent + 2); break; case NodeTypePrefixOpExpr: fprintf(f, "%s %s\n", node_type_str(node->type), @@ -631,8 +632,9 @@ static void render_node(AstRender *ar, AstNode *node) { fprintf(ar->f, "}"); break; case NodeTypeDirective: - fprintf(ar->f, "#%s(\"%s\")\n", buf_ptr(&node->data.directive.name), - buf_ptr(&node->data.directive.param)); + fprintf(ar->f, "#%s(", buf_ptr(&node->data.directive.name)); + render_node(ar, node->data.directive.expr); + fprintf(ar->f, ")\n"); break; case NodeTypeReturnExpr: zig_panic("TODO"); diff --git a/src/codegen.cpp b/src/codegen.cpp index 2d89d4aa5d..1c681ce6d9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2150,7 +2150,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { if (!g->is_release_build) { LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); } - return LLVMBuildUnreachable(g->builder); + LLVMBuildUnreachable(g->builder); + return nullptr; } else if (type_entry->id == TypeTableEntryIdVoid) { assert(node->data.container_init_expr.entries.length == 0); return nullptr; @@ -2487,6 +2488,13 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeSwitchExpr); + if (node->data.switch_expr.const_chosen_prong_index >= 0) { + AstNode *prong_node = node->data.switch_expr.prongs.at(node->data.switch_expr.const_chosen_prong_index); + assert(prong_node->type == NodeTypeSwitchProng); + AstNode *prong_expr = prong_node->data.switch_prong.expr; + return gen_expr(g, prong_expr); + } + TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr); LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr); LLVMValueRef target_value; @@ -3877,18 +3885,23 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, for (int i = 0; i < directives->length; i += 1) { AstNode *directive_node = directives->at(i); Buf *name = &directive_node->data.directive.name; - Buf *param = &directive_node->data.directive.param; - if (buf_eql_str(name, "version")) { - set_root_export_version(g, param, directive_node); - } else if (buf_eql_str(name, "link")) { - if (buf_eql_str(param, "c")) { - g->link_libc = true; + AstNode *param_node = directive_node->data.directive.expr; + assert(param_node->type == NodeTypeStringLiteral); + Buf *param = ¶m_node->data.string_literal.buf; + + if (param) { + if (buf_eql_str(name, "version")) { + set_root_export_version(g, param, directive_node); + } else if (buf_eql_str(name, "link")) { + if (buf_eql_str(param, "c")) { + g->link_libc = true; + } else { + g->link_libs.append(param); + } } else { - g->link_libs.append(param); + add_node_error(g, directive_node, + buf_sprintf("invalid directive: '%s'", buf_ptr(name))); } - } else { - add_node_error(g, directive_node, - buf_sprintf("invalid directive: '%s'", buf_ptr(name))); } } } diff --git a/src/link.cpp b/src/link.cpp index 40fad56ad8..4cc4281a91 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -580,35 +580,33 @@ static void construct_linker_job_darwin(LinkJob *lj) { lj->args.append("-o"); lj->args.append(buf_ptr(&lj->out_file)); - if (lj->link_in_crt) { - if (shared) { - zig_panic("TODO"); - } else if (g->is_static) { - lj->args.append("-lcrt0.o"); - } else { - switch (platform.kind) { - case MacOS: - if (darwin_version_lt(&platform, 10, 5)) { - lj->args.append("-lcrt1.o"); - } else if (darwin_version_lt(&platform, 10, 6)) { - lj->args.append("-lcrt1.10.5.o"); - } else if (darwin_version_lt(&platform, 10, 8)) { - lj->args.append("-lcrt1.10.6.o"); - } - break; - case IPhoneOS: - if (g->zig_target.arch.arch == ZigLLVM_aarch64) { - // iOS does not need any crt1 files for arm64 - } else if (darwin_version_lt(&platform, 3, 1)) { - lj->args.append("-lcrt1.o"); - } else if (darwin_version_lt(&platform, 6, 0)) { - lj->args.append("-lcrt1.3.1.o"); - } - break; - case IPhoneOSSimulator: - // no crt1.o needed - break; - } + if (shared) { + zig_panic("TODO"); + } else if (g->is_static) { + lj->args.append("-lcrt0.o"); + } else { + switch (platform.kind) { + case MacOS: + if (darwin_version_lt(&platform, 10, 5)) { + lj->args.append("-lcrt1.o"); + } else if (darwin_version_lt(&platform, 10, 6)) { + lj->args.append("-lcrt1.10.5.o"); + } else if (darwin_version_lt(&platform, 10, 8)) { + lj->args.append("-lcrt1.10.6.o"); + } + break; + case IPhoneOS: + if (g->zig_target.arch.arch == ZigLLVM_aarch64) { + // iOS does not need any crt1 files for arm64 + } else if (darwin_version_lt(&platform, 3, 1)) { + lj->args.append("-lcrt1.o"); + } else if (darwin_version_lt(&platform, 6, 0)) { + lj->args.append("-lcrt1.3.1.o"); + } + break; + case IPhoneOSSimulator: + // no crt1.o needed + break; } } @@ -620,29 +618,26 @@ static void construct_linker_job_darwin(LinkJob *lj) { lj->args.append((const char *)buf_ptr(&lj->out_file_o)); - if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) { - Buf *builtin_o_path = build_o(g, "builtin"); - lj->args.append(buf_ptr(builtin_o_path)); - } - for (int i = 0; i < g->link_libs.length; i += 1) { Buf *link_lib = g->link_libs.at(i); Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib)); lj->args.append(buf_ptr(arg)); } - if (g->link_libc) { - lj->args.append("-lSystem"); + // on Darwin, libSystem has libc in it, but also you have to use it + // to make syscalls because the syscall numbers are not documented + // and change between versions. + // so we always link against libSystem + lj->args.append("-lSystem"); - if (platform.kind == MacOS) { - if (darwin_version_lt(&platform, 10, 5)) { - lj->args.append("-lgcc_s.10.4"); - } else if (darwin_version_lt(&platform, 10, 6)) { - lj->args.append("-lgcc_s.10.5"); - } - } else { - zig_panic("TODO"); + if (platform.kind == MacOS) { + if (darwin_version_lt(&platform, 10, 5)) { + lj->args.append("-lgcc_s.10.4"); + } else if (darwin_version_lt(&platform, 10, 6)) { + lj->args.append("-lgcc_s.10.5"); } + } else { + zig_panic("TODO"); } } diff --git a/src/parser.cpp b/src/parser.cpp index 5d22105bff..1a5cc503cd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -499,6 +499,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory, ZigList *directives, VisibMod visib_mod); static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index); +static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool mandatory); static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { if (token->id == token_id) { @@ -517,33 +518,19 @@ static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id return token; } - +/* +Directive = "#" "Symbol" "(" Expression ")" +*/ static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) { - Token *number_sign = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, number_sign, TokenIdNumberSign); + Token *number_sign = ast_eat_token(pc, token_index, TokenIdNumberSign); AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign); - Token *name_symbol = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, name_symbol, TokenIdSymbol); + Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol); ast_buf_from_token(pc, name_symbol, &node->data.directive.name); - Token *l_paren = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, l_paren, TokenIdLParen); - - Token *param_str = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, param_str, TokenIdStringLiteral); - - parse_string_literal(pc, param_str, &node->data.directive.param, nullptr, nullptr); - - Token *r_paren = &pc->tokens->at(*token_index); - *token_index += 1; - ast_expect_token(pc, r_paren, TokenIdRParen); + node->data.directive.expr = ast_parse_grouped_expr(pc, token_index, true); normalize_parent_ptrs(node); return node; @@ -2741,7 +2728,7 @@ void normalize_parent_ptrs(AstNode *node) { set_list_fields(&node->data.block.statements); break; case NodeTypeDirective: - // none + set_field(&node->data.directive.expr); break; case NodeTypeReturnExpr: set_field(&node->data.return_expr.expr); diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 091d7c77ca..f0f177dbfd 100644 --- a/std/bootstrap.zig +++ b/std/bootstrap.zig @@ -1,24 +1,28 @@ import "syscall.zig"; // The compiler treats this file special by implicitly importing the function `main` -// from the root source file. +// from the root source file as the symbol `zig_user_main`. + +const want_start_symbol = switch(@compile_var("os")) { + linux => true, + else => false, +}; +const want_main_symbol = !want_start_symbol; var argc: isize = undefined; var argv: &&u8 = undefined; -var env: &&u8 = undefined; #attribute("naked") +#condition(want_start_symbol) export fn _start() -> unreachable { switch (@compile_var("arch")) { x86_64 => { argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize)); argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8)); - env = asm("lea 0x10(%%rsp,[argc],8), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc)); }, i386 => { argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> isize)); argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8)); - env = asm("lea 0x8(%%esp,%[argc],4), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc)); }, else => unreachable{}, } @@ -39,6 +43,17 @@ fn call_main() -> unreachable { const ptr = argv[i]; args[i] = ptr[0...strlen(ptr)]; } - main(args) %% exit(1); + zig_user_main(args) %% exit(1); exit(0); } + +#condition(want_main_symbol) +export fn main(argc: i32, argv: &&u8) -> i32 { + var args: [argc][]u8 = undefined; + for (args) |arg, i| { + const ptr = argv[i]; + args[i] = ptr[0...strlen(ptr)]; + } + zig_user_main(args) %% return 1; + return 0; +}