From: Michael Urman <mu@tortall.net>
Date: Sat, 12 Mar 2005 05:06:50 +0000 (-0000)
Subject: Add `hidden' `internal' and `protected' symbol visibility types to
X-Git-Tag: v0.5.0rc1~172
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3cc450d3ea88c4e22cd16b2459bef8c7b3f124ef;p=yasm

Add `hidden' `internal' and `protected' symbol visibility types to
global symbols in ELF. Search for STV_HIDDEN for explanations; these
don't seem to appear in the base ELF documentation.

Sample syntax:
    global foo:hidden

Inspiration and base patch provided by Oskari Saarenmaa under our BSD
license. This checkin tweaks and extends Oskari's patch and adds tests.

svn path=/trunk/yasm/; revision=1202
---

diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c
index 8b5c84ae..59bff2f3 100644
--- a/modules/objfmts/elf/elf-objfmt.c
+++ b/modules/objfmts/elf/elf-objfmt.c
@@ -86,8 +86,8 @@ yasm_objfmt_module yasm_elf_LTX_objfmt;
 static elf_symtab_entry *
 elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,
 			 elf_section_index sectidx, elf_symbol_binding bind,
-			 elf_symbol_type type, yasm_expr *size,
-			 elf_address value)
+			 elf_symbol_type type, elf_symbol_vis vis,
+                         yasm_expr *size, elf_address value)
 {
     elf_strtab_entry *name = elf_strtab_append_str(objfmt_elf->strtab,
 						   yasm_symrec_get_name(sym));
@@ -95,6 +95,7 @@ elf_objfmt_symtab_append(yasm_objfmt_elf *objfmt_elf, yasm_symrec *sym,
     elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
 
     elf_symtab_set_nonzero(entry, NULL, sectidx, bind, type, size, value);
+    elf_sym_set_visibility(entry, vis);
     yasm_symrec_add_data(sym, &elf_symrec_data, entry);
 
     return entry;
@@ -822,8 +823,16 @@ elf_objfmt_extern_declare(yasm_objfmt *objfmt, const char *name, /*@unused@*/
 
     sym = yasm_symtab_declare(objfmt_elf->symtab, name, YASM_SYM_EXTERN, line);
     elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
-			     STT_NOTYPE, NULL, 0);
+                             STT_NOTYPE, STV_DEFAULT, NULL, 0);
 
+    if (objext_valparams) {
+	yasm_valparam *vp = yasm_vps_first(objext_valparams);
+	for (; vp; vp = yasm_vps_next(vp))
+        {
+            if (vp->val)
+                yasm__error(line, N_("unrecognized symbol type `%s'"), vp->val);
+        }
+    }
     return sym;
 }
 
@@ -836,30 +845,50 @@ elf_objfmt_global_declare(yasm_objfmt *objfmt, const char *name,
     yasm_symrec *sym;
     elf_symbol_type type = STT_NOTYPE;
     yasm_expr *size = NULL;
+    elf_symbol_vis vis = STV_DEFAULT;
+    unsigned int vis_overrides = 0;
 
     sym = yasm_symtab_declare(objfmt_elf->symtab, name, YASM_SYM_GLOBAL, line);
 
     if (objext_valparams) {
 	yasm_valparam *vp = yasm_vps_first(objext_valparams);
-	if (vp && vp->val) {
-	    if (yasm__strcasecmp(vp->val, "function") == 0)
-		type = STT_FUNC;
-	    else if (yasm__strcasecmp(vp->val, "data") == 0 ||
-		     yasm__strcasecmp(vp->val, "object") == 0)
-		type = STT_OBJECT;
-	    else
-		yasm__error(line, N_("unrecognized symbol type `%s'"),
-			    vp->val);
-	    vp = yasm_vps_next(vp);
-	}
-	if (vp && !vp->val && vp->param) {
-	    size = vp->param;
-	    vp->param = NULL;	/* to avoid deleting the expr */
+	for (; vp; vp = yasm_vps_next(vp))
+        {
+            if (vp->val) {
+                if (yasm__strcasecmp(vp->val, "function") == 0)
+                    type = STT_FUNC;
+                else if (yasm__strcasecmp(vp->val, "data") == 0 ||
+                         yasm__strcasecmp(vp->val, "object") == 0)
+                    type = STT_OBJECT;
+                else if (yasm__strcasecmp(vp->val, "internal") == 0) {
+                    vis = STV_INTERNAL;
+                    vis_overrides++;
+                }
+                else if (yasm__strcasecmp(vp->val, "hidden") == 0) {
+                    vis = STV_HIDDEN;
+                    vis_overrides++;
+                }
+                else if (yasm__strcasecmp(vp->val, "protected") == 0) {
+                    vis = STV_PROTECTED;
+                    vis_overrides++;
+                }
+                else
+                    yasm__error(line, N_("unrecognized symbol type `%s'"),
+                                vp->val);
+            }
+            else if (vp->param && !size) {
+                size = vp->param;
+                vp->param = NULL;	/* to avoid deleting the expr */
+            }
 	}
+        if (vis_overrides > 1) {
+            yasm__warning(YASM_WARN_GENERAL, line,
+                N_("More than one symbol visibility provided; using last"));
+        }
     }
 
     elf_objfmt_symtab_append(objfmt_elf, sym, SHN_UNDEF, STB_GLOBAL,
-			     type, size, 0);
+                             type, vis, size, 0);
 
     return sym;
 }
@@ -878,30 +907,32 @@ elf_objfmt_common_declare(yasm_objfmt *objfmt, const char *name,
 
     if (objext_valparams) {
 	yasm_valparam *vp = yasm_vps_first(objext_valparams);
-	if (vp && !vp->val && vp->param) {
-            /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
-
-            align_expr = yasm_expr_get_intnum(&vp->param, NULL);
-            if (!align_expr) {
-                yasm__error(line,
-                            N_("alignment constraint is not a power of two"));
-                return sym;
-            }
-            addralign = yasm_intnum_get_uint(align_expr);
-
-            /* Alignments must be a power of two. */
-            if ((addralign & (addralign - 1)) != 0) {
-                yasm__error(line,
-                            N_("alignment constraint is not a power of two"));
-                return sym;
-            }
-	} else if (vp && vp->val)
-	    yasm__warning(YASM_WARN_GENERAL, line,
-			  N_("Unrecognized qualifier `%s'"), vp->val);
+        for (; vp; vp = yasm_vps_next(vp)) {
+            if (!vp->val && vp->param) {
+                /*@dependent@*/ /*@null@*/ const yasm_intnum *align_expr;
+
+                align_expr = yasm_expr_get_intnum(&vp->param, NULL);
+                if (!align_expr) {
+                    yasm__error(line,
+                                N_("alignment constraint is not a power of two"));
+                    return sym;
+                }
+                addralign = yasm_intnum_get_uint(align_expr);
+
+                /* Alignments must be a power of two. */
+                if ((addralign & (addralign - 1)) != 0) {
+                    yasm__error(line,
+                                N_("alignment constraint is not a power of two"));
+                    return sym;
+                }
+            } else if (vp->val)
+                yasm__warning(YASM_WARN_GENERAL, line,
+                              N_("Unrecognized qualifier `%s'"), vp->val);
+        }
     }
 
     elf_objfmt_symtab_append(objfmt_elf, sym, SHN_COMMON, STB_GLOBAL,
-			     STT_NOTYPE, size, addralign);
+                             STT_NOTYPE, STV_DEFAULT, size, addralign);
 
     return sym;
 }
diff --git a/modules/objfmts/elf/elf-x86-amd64.c b/modules/objfmts/elf/elf-x86-amd64.c
index 29542f92..27bfb1c3 100644
--- a/modules/objfmts/elf/elf-x86-amd64.c
+++ b/modules/objfmts/elf/elf-x86-amd64.c
@@ -63,7 +63,7 @@ elf_x86_amd64_write_symtab_entry(unsigned char *bufp,
 {
     YASM_WRITE_32_L(bufp, entry->name ? entry->name->index : 0);
     YASM_WRITE_8(bufp, ELF64_ST_INFO(entry->bind, entry->type));
-    YASM_WRITE_8(bufp, 0);
+    YASM_WRITE_8(bufp, ELF64_ST_OTHER(entry->vis));
     if (entry->sect) {
         if (yasm_section_is_absolute(entry->sect)) {
             YASM_WRITE_16_L(bufp, SHN_ABS);
diff --git a/modules/objfmts/elf/elf-x86-x86.c b/modules/objfmts/elf/elf-x86-x86.c
index e20150ea..d585a398 100644
--- a/modules/objfmts/elf/elf-x86-x86.c
+++ b/modules/objfmts/elf/elf-x86-x86.c
@@ -68,7 +68,7 @@ elf_x86_x86_write_symtab_entry(unsigned char *bufp,
     YASM_WRITE_32I_L(bufp, size_intn);
 
     YASM_WRITE_8(bufp, ELF32_ST_INFO(entry->bind, entry->type));
-    YASM_WRITE_8(bufp, 0);
+    YASM_WRITE_8(bufp, ELF32_ST_OTHER(entry->vis));
     if (entry->sect) {
         if (yasm_section_is_absolute(entry->sect)) {
             YASM_WRITE_16_L(bufp, SHN_ABS);
diff --git a/modules/objfmts/elf/elf.c b/modules/objfmts/elf/elf.c
index 1af53597..3cfa772d 100644
--- a/modules/objfmts/elf/elf.c
+++ b/modules/objfmts/elf/elf.c
@@ -252,6 +252,7 @@ elf_symtab_entry_create(elf_strtab_entry *name,
     entry->index = 0;
     entry->bind = 0;
     entry->type = STT_NOTYPE;
+    entry->vis = STV_DEFAULT;
 
     return entry;
 }
@@ -324,6 +325,7 @@ elf_symtab_create()
     entry->index = SHN_UNDEF;
     entry->bind = 0;
     entry->type = 0;
+    entry->vis = STV_DEFAULT;
     entry->symindex = 0;
     STAILQ_INSERT_TAIL(symtab, entry, qlink);
     return symtab;
@@ -489,6 +491,12 @@ void elf_symtab_set_nonzero(elf_symtab_entry *entry,
     if (value) entry->value = value;
 }
 
+void
+elf_sym_set_visibility(elf_symtab_entry *entry,
+                       elf_symbol_vis    vis)
+{
+    entry->vis = ELF_ST_VISIBILITY(vis);
+}                            
 
 elf_secthead *
 elf_secthead_create(elf_strtab_entry	*name,
diff --git a/modules/objfmts/elf/elf.h b/modules/objfmts/elf/elf.h
index 10208c5c..5c579138 100644
--- a/modules/objfmts/elf/elf.h
+++ b/modules/objfmts/elf/elf.h
@@ -196,15 +196,28 @@ typedef enum {
     STN_UNDEF = 0
 } elf_symbol_index;
 
+/* elf symbol visibility - lower two bits of OTHER field */
+typedef enum {
+    STV_DEFAULT = 0,		/* Default symbol visibility rules */
+    STV_INTERNAL = 1,		/* Processor specific hidden class */
+    STV_HIDDEN = 2,		/* Sym unavailable in other modules */
+    STV_PROTECTED = 3		/* Not preemptable, not exported */
+} elf_symbol_vis;
+
 
 /* internal only object definitions */
 #ifdef YASM_OBJFMT_ELF_INTERNAL
 
+#define ELF_VISIBILITY_MASK		0x03
+#define ELF_ST_VISIBILITY(v)            ((v) & ELF_VISIBILITY_MASK)
+
 #define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
 #define ELF32_R_INFO(s,t)		(((s)<<8)+(unsigned char)(t))
+#define ELF32_ST_OTHER(vis)             ELF_ST_VISIBILITY(vis)
 
 #define ELF64_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
 #define ELF64_R_INFO(s,t)		(((s)<<32) + ((t) & 0xffffffffL))
+#define ELF64_ST_OTHER(vis)             ELF_ST_VISIBILITY(vis)
 
 #define EHDR32_SIZE 52
 #define EHDR64_SIZE 64
@@ -376,6 +389,7 @@ struct elf_symtab_entry {
     elf_section_index	 index;
     elf_symbol_binding	 bind;
     elf_symbol_type	 type;
+    elf_symbol_vis       vis;
     elf_symbol_index	 symindex;
 };
 
@@ -422,7 +436,8 @@ void elf_symtab_set_nonzero(elf_symtab_entry	*entry,
 			    elf_symbol_type	 type,
 			    struct yasm_expr	*size,
 			    elf_address		 value);
-
+void elf_sym_set_visibility(elf_symtab_entry    *entry,
+                            elf_symbol_vis       vis);
 
 /* section header functions */
 elf_secthead *elf_secthead_create(elf_strtab_entry	*name,
diff --git a/modules/objfmts/elf/tests/Makefile.inc b/modules/objfmts/elf/tests/Makefile.inc
index dee1cb8a..51d51b06 100644
--- a/modules/objfmts/elf/tests/Makefile.inc
+++ b/modules/objfmts/elf/tests/Makefile.inc
@@ -34,6 +34,9 @@ EXTRA_DIST += modules/objfmts/elf/tests/elfreloc-ext.hex
 EXTRA_DIST += modules/objfmts/elf/tests/elfabssect.asm
 EXTRA_DIST += modules/objfmts/elf/tests/elfabssect.errwarn
 EXTRA_DIST += modules/objfmts/elf/tests/elfabssect.hex
+EXTRA_DIST += modules/objfmts/elf/tests/elfvisibility.asm
+EXTRA_DIST += modules/objfmts/elf/tests/elfvisibility.errwarn
+EXTRA_DIST += modules/objfmts/elf/tests/elfvisibility.hex
 
 EXTRA_DIST += modules/objfmts/elf/tests/amd64/Makefile.inc
 
diff --git a/modules/objfmts/elf/tests/elfvisibility.asm b/modules/objfmts/elf/tests/elfvisibility.asm
new file mode 100644
index 00000000..13203106
--- /dev/null
+++ b/modules/objfmts/elf/tests/elfvisibility.asm
@@ -0,0 +1,6 @@
+[section .text]
+
+global ghidden:hidden
+global ginternal:internal
+global gprotected:protected
+global gtoomany:hidden internal
diff --git a/modules/objfmts/elf/tests/elfvisibility.errwarn b/modules/objfmts/elf/tests/elfvisibility.errwarn
new file mode 100644
index 00000000..968dc9bb
--- /dev/null
+++ b/modules/objfmts/elf/tests/elfvisibility.errwarn
@@ -0,0 +1 @@
+-:6: warning: More than one symbol visibility provided; using last
diff --git a/modules/objfmts/elf/tests/elfvisibility.hex b/modules/objfmts/elf/tests/elfvisibility.hex
new file mode 100644
index 00000000..8b2d2cb0
--- /dev/null
+++ b/modules/objfmts/elf/tests/elfvisibility.hex
@@ -0,0 +1,456 @@
+7f 
+45 
+4c 
+46 
+01 
+01 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+03 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+34 
+00 
+00 
+00 
+00 
+00 
+28 
+00 
+05 
+00 
+01 
+00 
+00 
+2e 
+74 
+65 
+78 
+74 
+00 
+2e 
+73 
+74 
+72 
+74 
+61 
+62 
+00 
+2e 
+73 
+79 
+6d 
+74 
+61 
+62 
+00 
+2e 
+73 
+68 
+73 
+74 
+72 
+74 
+61 
+62 
+00 
+00 
+00 
+00 
+00 
+2d 
+00 
+67 
+68 
+69 
+64 
+64 
+65 
+6e 
+00 
+67 
+69 
+6e 
+74 
+65 
+72 
+6e 
+61 
+6c 
+00 
+67 
+70 
+72 
+6f 
+74 
+65 
+63 
+74 
+65 
+64 
+00 
+67 
+74 
+6f 
+6f 
+6d 
+61 
+6e 
+79 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+04 
+00 
+f1 
+ff 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+02 
+00 
+00 
+0b 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+01 
+00 
+00 
+15 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+03 
+00 
+00 
+20 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+01 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+17 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+34 
+00 
+00 
+00 
+21 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+07 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+58 
+00 
+00 
+00 
+29 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+0f 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+84 
+00 
+00 
+00 
+70 
+00 
+00 
+00 
+02 
+00 
+00 
+00 
+03 
+00 
+00 
+00 
+04 
+00 
+00 
+00 
+10 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+01 
+00 
+00 
+00 
+06 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+00 
+10 
+00 
+00 
+00 
+00 
+00 
+00 
+00