aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tcc.h12
-rw-r--r--tccgen.c60
-rw-r--r--tcctok.h2
3 files changed, 69 insertions, 5 deletions
diff --git a/tcc.h b/tcc.h
index dda2fc1..ab14b38 100644
--- a/tcc.h
+++ b/tcc.h
@@ -375,7 +375,8 @@ struct Attribute {
func_proto : 1,
mode : 4,
weak : 1,
- fill : 10; // 10 bits left to fit well in union below
+ visibility : 2,
+ fill : 8; // 8 bits left to fit well in union below
};
/* GNUC attribute definition */
@@ -787,11 +788,18 @@ struct TCCState {
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
#define VT_WEAK 0x00010000 /* weak symbol */
#define VT_TLS 0x00040000 /* thread-local storage */
+#define VT_VIS_SHIFT 19 /* shift for symbol visibility, overlapping
+ bitfield values, because bitfields never
+ have linkage and hence never have
+ visibility. */
+#define VT_VIS_SIZE 2 /* We have four visibilities. */
+#define VT_VIS_MASK (((1 << VT_VIS_SIZE)-1) << VT_VIS_SHIFT)
#define VT_STRUCT_SHIFT 19 /* shift for bitfield shift values (max: 32 - 2*6) */
+
/* type mask (except storage) */
-#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK)
+#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_IMPORT | VT_EXPORT | VT_WEAK | VT_VIS_MASK)
#define VT_TYPE (~(VT_STORAGE))
/* token values */
diff --git a/tccgen.c b/tccgen.c
index 78f24aa..9b00824 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -300,6 +300,29 @@ static void weaken_symbol(Sym *sym)
}
}
+static void apply_visibility(Sym *sym, CType *type)
+{
+ int vis = sym->type.t & VT_VIS_MASK;
+ int vis2 = type->t & VT_VIS_MASK;
+ if (vis == (STV_DEFAULT << VT_VIS_SHIFT))
+ vis = vis2;
+ else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT))
+ ;
+ else
+ vis = (vis < vis2) ? vis : vis2;
+ sym->type.t &= ~VT_VIS_MASK;
+ sym->type.t |= vis;
+
+ if (sym->c > 0) {
+ int esym_type;
+ ElfW(Sym) *esym;
+
+ esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
+ vis >>= VT_VIS_SHIFT;
+ esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis;
+ }
+}
+
/* ------------------------------------------------------------------------- */
ST_FUNC void swap(int *p, int *q)
@@ -436,6 +459,13 @@ static Sym *external_sym(int v, CType *type, int r, char *asm_label)
tcc_error("incompatible types for redefinition of '%s'",
get_tok_str(v, NULL));
}
+ /* Merge some storage attributes. */
+ if (type->t & VT_WEAK)
+ weaken_symbol(s);
+
+ if (type->t & VT_VIS_MASK)
+ apply_visibility(s, type);
+
return s;
}
@@ -2662,6 +2692,24 @@ static void parse_attribute(AttributeDef *ad)
next();
skip(')');
break;
+ case TOK_VISIBILITY1:
+ case TOK_VISIBILITY2:
+ skip('(');
+ if (tok != TOK_STR)
+ expect("visibility(\"default|hidden|internal|protected\")");
+ if (!strcmp (tokc.cstr->data, "default"))
+ ad->a.visibility = STV_DEFAULT;
+ else if (!strcmp (tokc.cstr->data, "hidden"))
+ ad->a.visibility = STV_HIDDEN;
+ else if (!strcmp (tokc.cstr->data, "internal"))
+ ad->a.visibility = STV_INTERNAL;
+ else if (!strcmp (tokc.cstr->data, "protected"))
+ ad->a.visibility = STV_PROTECTED;
+ else
+ expect("visibility(\"default|hidden|internal|protected\")");
+ next();
+ skip(')');
+ break;
case TOK_ALIGNED1:
case TOK_ALIGNED2:
if (tok == '(') {
@@ -5656,6 +5704,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* patch symbol weakness */
if (type->t & VT_WEAK)
weaken_symbol(sym);
+ apply_visibility(sym, type);
#ifdef CONFIG_TCC_BCHECK
/* handles bounds now because the symbol must be defined
before for the relocation */
@@ -5801,6 +5850,7 @@ static void gen_function(Sym *sym)
/* patch symbol weakness (this definition overrules any prototype) */
if (sym->type.t & VT_WEAK)
weaken_symbol(sym);
+ apply_visibility(sym, &sym->type);
if (tcc_state->do_debug) {
put_stabn(N_FUN, 0, 0, ind - func_ind);
}
@@ -5934,6 +5984,8 @@ static int decl0(int l, int is_for_loop_init)
if (ad.a.func_export)
type.t |= VT_EXPORT;
#endif
+ type.t |= ad.a.visibility << VT_VIS_SHIFT;
+
if (tok == '{') {
if (l == VT_LOCAL)
tcc_error("cannot use local functions");
@@ -5973,6 +6025,11 @@ static int decl0(int l, int is_for_loop_init)
if (sym->type.t & VT_STATIC)
type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
+ /* If the definition has no visibility use the
+ one from prototype. */
+ if (! (type.t & VT_VIS_MASK))
+ type.t |= sym->type.t & VT_VIS_MASK;
+
if (!is_compatible_types(&sym->type, &type)) {
func_error1:
tcc_error("incompatible types for redefinition of '%s'",
@@ -6063,9 +6120,6 @@ static int decl0(int l, int is_for_loop_init)
extern */
sym = external_sym(v, &type, r, asm_label);
- if (type.t & VT_WEAK)
- weaken_symbol(sym);
-
if (ad.alias_target) {
Section tsec;
Elf32_Sym *esym;
diff --git a/tcctok.h b/tcctok.h
index c17711f..d8c0344 100644
--- a/tcctok.h
+++ b/tcctok.h
@@ -121,6 +121,8 @@
DEF(TOK_DLLIMPORT, "dllimport")
DEF(TOK_NORETURN1, "noreturn")
DEF(TOK_NORETURN2, "__noreturn__")
+ DEF(TOK_VISIBILITY1, "visibility")
+ DEF(TOK_VISIBILITY2, "__visibility__")
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_builtin_frame_address, "__builtin_frame_address")