diff --git a/include/elf.h b/include/elf.h index 9403d213e..bf1a5ef16 100644 --- a/include/elf.h +++ b/include/elf.h @@ -114,6 +114,8 @@ typedef struct { #define STB_GLOBAL (1) #define STT_NOTYPE (0) +#define STT_OBJECT (1) +#define STT_FUNC (2) #define STT_SECTION (3) #define ELF64_ST_BIND(info) ((info) >> 4) diff --git a/src/as/as.c b/src/as/as.c index 4faf41a88..1a06e8de9 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -102,7 +102,13 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { if (!(info->flag & LF_GLOBAL) || !(info->flag & LF_DEFINED)) continue; sym = symtab_add(&symtab, name); - sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); + int type; + switch (info->kind) { + case LK_NONE: type = STT_NOTYPE; break; + case LK_FUNC: type = STT_FUNC; break; + case LK_OBJECT: type = STT_OBJECT; break; + } + sym->st_info = ELF64_ST_INFO(STB_GLOBAL, type); sym->st_value = info->address - section_start_addresses[info->section]; sym->st_shndx = info->section + 1; // Symbol index for Local section. } diff --git a/src/as/inst.h b/src/as/inst.h index 1649c97d8..1d93d7c43 100644 --- a/src/as/inst.h +++ b/src/as/inst.h @@ -309,6 +309,7 @@ enum DirectiveType { DT_DATA, DT_ALIGN, DT_P2ALIGN, + DT_TYPE, DT_BYTE, DT_SHORT, DT_LONG, diff --git a/src/as/ir_asm.c b/src/as/ir_asm.c index 21f211524..4be16f924 100644 --- a/src/as/ir_asm.c +++ b/src/as/ir_asm.c @@ -20,16 +20,17 @@ static LabelInfo *new_label(int section, uintptr_t address) { info->section = section; info->flag = 0; info->address = address; + info->kind = LK_NONE; return info; } -bool add_label_table(Table *label_table, const Name *label, int section, bool define, bool global) { +LabelInfo *add_label_table(Table *label_table, const Name *label, int section, bool define, bool global) { LabelInfo *info = table_get(label_table, label); if (info != NULL) { if (define) { if ((info->flag & LF_DEFINED) != 0) { fprintf(stderr, "`%.*s' already defined\n", NAMES(label)); - return false; + return NULL; } info->address = 1; info->section = section; @@ -42,7 +43,7 @@ bool add_label_table(Table *label_table, const Name *label, int section, bool de info->flag |= LF_DEFINED; if (global) info->flag |= LF_GLOBAL; - return true; + return info; } IR *new_ir_label(const Name *label) { diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index ae08c43fc..97a89892b 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -15,13 +15,20 @@ typedef struct Vector Vector; #define LF_GLOBAL (1 << 0) #define LF_DEFINED (1 << 1) +enum LabelKind { + LK_NONE, + LK_FUNC, + LK_OBJECT, +}; + typedef struct { int section; int flag; uintptr_t address; + enum LabelKind kind; } LabelInfo; -bool add_label_table(Table *label_table, const Name *label, int section, bool define, bool global); +LabelInfo *add_label_table(Table *label_table, const Name *label, int section, bool define, bool global); enum UnresolvedKind { UNRES_EXTERN, diff --git a/src/as/parse_asm.c b/src/as/parse_asm.c index 9b94787ec..b6acef789 100644 --- a/src/as/parse_asm.c +++ b/src/as/parse_asm.c @@ -219,6 +219,7 @@ static const char *kDirectiveTable[] = { "data", "align", "p2align", + "type", "byte", "short", "long", @@ -403,13 +404,28 @@ static const Name *parse_label(ParseInfo *info) { return alloc_name(start + 1, p - 1, false); } - if (!is_label_first_chr(*p)) + unsigned char *q = (unsigned char*)p; + int uc = *q; + int ucc = isutf8first(uc) - 1; + if (!(ucc > 0 || is_label_first_chr(uc))) return NULL; - do { - ++p; - } while (is_label_chr(*p)); - info->p = p; + for (;;) { + uc = *++q; + if (ucc > 0) { + if (!isutf8follow(uc)) { + parse_error(info, "Illegal byte sequence"); + return NULL; + } + --ucc; + continue; + } + if ((ucc = isutf8first(uc) - 1) > 0) + continue; + if (!is_label_chr(uc)) + break; + } + info->p = p = (char*)q; return alloc_name(start, p, false); } @@ -1106,6 +1122,35 @@ void handle_directive(ParseInfo *info, enum DirectiveType dir, Vector **section_ } break; + case DT_TYPE: + { + const Name *label = parse_label(info); + if (label == NULL) { + parse_error(info, ".comm: label expected"); + break; + } + if (*info->p != ',') { + parse_error(info, ".comm: `,' expected"); + break; + } + info->p = skip_whitespaces(info->p + 1); + enum LabelKind kind = LK_NONE; + if (strcmp(info->p, "@function") == 0) { + kind = LK_FUNC; + } else if (strcmp(info->p, "@object") == 0) { + kind = LK_OBJECT; + } else { + parse_error(info, "illegal .type"); + break; + } + + LabelInfo *info = add_label_table(label_table, label, current_section, false, false); + if (info != NULL) { + info->kind = kind; + } + } + break; + case DT_BYTE: case DT_SHORT: case DT_LONG: diff --git a/src/cc/arch/aarch64/emit_code.c b/src/cc/arch/aarch64/emit_code.c index 3a7e4fb53..394f60309 100644 --- a/src/cc/arch/aarch64/emit_code.c +++ b/src/cc/arch/aarch64/emit_code.c @@ -168,6 +168,9 @@ static void emit_defun(Function *func) { _LOCAL(label); } EMIT_ALIGN(4); +#if XCC_TARGET_PLATFORM != XCC_PLATFORM_APPLE + EMIT_ASM(".type", fmt("%.*s", NAMES(func->name)), "@function"); +#endif EMIT_LABEL(label); bool no_stmt = true; diff --git a/src/cc/arch/riscv64/emit_code.c b/src/cc/arch/riscv64/emit_code.c index 17d00425b..b5cde520d 100644 --- a/src/cc/arch/riscv64/emit_code.c +++ b/src/cc/arch/riscv64/emit_code.c @@ -143,6 +143,9 @@ static void emit_defun(Function *func) { _LOCAL(label); } EMIT_ALIGN(2); +#if XCC_TARGET_PLATFORM != XCC_PLATFORM_APPLE + EMIT_ASM(".type", fmt("%.*s", NAMES(func->name)), "@function"); +#endif EMIT_LABEL(label); bool no_stmt = true; diff --git a/src/cc/arch/x64/emit_code.c b/src/cc/arch/x64/emit_code.c index ca85bc76a..dcfd4fec9 100644 --- a/src/cc/arch/x64/emit_code.c +++ b/src/cc/arch/x64/emit_code.c @@ -165,6 +165,9 @@ static void emit_defun(Function *func) { label = quote_label(label); _LOCAL(label); } +#if XCC_TARGET_PLATFORM != XCC_PLATFORM_APPLE + EMIT_ASM(".type", fmt("%.*s", NAMES(func->name)), "@function"); +#endif EMIT_LABEL(label); bool no_stmt = true; diff --git a/src/cc/backend/emit_util.c b/src/cc/backend/emit_util.c index 89985dd60..5775a8f43 100644 --- a/src/cc/backend/emit_util.c +++ b/src/cc/backend/emit_util.c @@ -244,6 +244,9 @@ void emit_varinfo(const VarInfo *varinfo, const Initializer *init) { label = quote_label(label); _LOCAL(label); } +#if XCC_TARGET_PLATFORM != XCC_PLATFORM_APPLE + EMIT_ASM(".type", fmt("%.*s", NAMES(name)), "@object"); +#endif if (init != NULL) { EMIT_ALIGN(align_size(varinfo->type)); diff --git a/src/ld/elfobj.c b/src/ld/elfobj.c index 7a24b6890..3ef3ba543 100644 --- a/src/ld/elfobj.c +++ b/src/ld/elfobj.c @@ -91,7 +91,7 @@ static bool load_symtab(ElfObj *elfobj) { for (uint32_t i = 0; i < count; ++i) { Elf64_Sym *sym = &symbols[i]; unsigned char type = ELF64_ST_TYPE(sym->st_info); - if (type == STT_NOTYPE && str[sym->st_name] != '\0') { + if (type != STT_SECTION && str[sym->st_name] != '\0') { const Name *name = alloc_name(&str[sym->st_name], NULL, false); table_put(symbol_table, name, sym); }