added elf-visibility handling
authorMatthias Braun <matze@braunis.de>
Thu, 9 Jun 2011 11:43:47 +0000 (13:43 +0200)
committerMatthias Braun <matze@braunis.de>
Thu, 9 Jun 2011 11:43:47 +0000 (13:43 +0200)
Currently only used for jna export though.

attribute.c
entity.c
entity_t.h
main.c
parser.c
parser.h
wrappergen/write_jna.c

index 3eafe94..651c6ee 100644 (file)
@@ -233,9 +233,64 @@ static void handle_attribute_aligned(const attribute_t *attribute,
                break;
        default:
                if (warning.other) {
+                       const char *what = get_entity_kind_name(entity->kind);
                        warningf(&attribute->source_position,
-                                        "alignment attribute specification on '%S' ignored",
-                                        entity->base.symbol);
+                                        "alignment attribute specification on %s '%S' ignored",
+                                        what, entity->base.symbol);
+               }
+               break;
+       }
+}
+
+static const char *get_argument_string(const attribute_argument_t *argument)
+{
+       if (argument == NULL)
+               return NULL;
+       if (argument->kind != ATTRIBUTE_ARGUMENT_EXPRESSION)
+               return NULL;
+       expression_t *expression = argument->v.expression;
+       if (expression->kind != EXPR_STRING_LITERAL)
+               return NULL;
+       return expression->literal.value.begin;
+}
+
+static void handle_attribute_visibility(const attribute_t *attribute,
+                                        entity_t *entity)
+{
+       /* This isn't really correct, the backend should provide a list of machine
+        * specific modes (according to gcc philosophy that is...) */
+       attribute_argument_t *arg = attribute->a.arguments;
+       if (arg == NULL) {
+               errorf(&attribute->source_position,
+                      "__attribute__((visibility(X))) misses argument");
+               return;
+       }
+       const char *string = get_argument_string(arg);
+       if (string == NULL) {
+               errorf(&attribute->source_position,
+                      "__attribute__((visibility(X))) argument is not a string");
+               return;
+       }
+       elf_visibility_tag_t visibility = get_elf_visibility_from_string(string);
+       if (visibility == ELF_VISIBILITY_ERROR) {
+               errorf(&attribute->source_position,
+                      "unknown visibility type '%s'", string);
+               return;
+       }
+
+       switch (entity->kind) {
+       case ENTITY_VARIABLE:
+               entity->variable.elf_visibility = visibility;
+               break;
+       case ENTITY_FUNCTION:
+               entity->function.elf_visibility = visibility;
+               break;
+       default:
+               if (warning.other) {
+                       const char *what = get_entity_kind_name(entity->kind);
+                       warningf(&attribute->source_position,
+                                        "visibility attribute specification on %s '%S' ignored",
+                                        what, entity->base.symbol);
                }
                break;
        }
@@ -354,6 +409,10 @@ void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
                        handle_attribute_asm(attribute, entity);
                        break;
 
+               case ATTRIBUTE_GNU_VISIBILITY:
+                       handle_attribute_visibility(attribute, entity);
+                       break;
+
                case ATTRIBUTE_MS_ALIGN:
                case ATTRIBUTE_GNU_ALIGNED:
                        handle_attribute_aligned(attribute, entity);
@@ -438,14 +497,7 @@ const char *get_deprecated_string(const attribute_t *attribute)
                        continue;
 
                attribute_argument_t *argument = attribute->a.arguments;
-               if (argument == NULL)
-                       return NULL;
-               if (argument->kind != ATTRIBUTE_ARGUMENT_EXPRESSION)
-                       return NULL;
-               expression_t *expression = argument->v.expression;
-               if (expression->kind != EXPR_STRING_LITERAL)
-                       return NULL;
-               return expression->literal.value.begin;
+               return get_argument_string(argument);
        }
        return NULL;
 }
index 748ead0..89d69e3 100644 (file)
--- a/entity.c
+++ b/entity.c
@@ -25,6 +25,7 @@
 #include "ast_t.h"
 #include "adt/error.h"
 #include "adt/util.h"
+#include "adt/strutil.h"
 
 const char *get_entity_kind_name(entity_kind_t kind)
 {
@@ -87,3 +88,18 @@ entity_t *allocate_entity_zero(entity_kind_t kind)
        entity->kind     = kind;
        return entity;
 }
+
+elf_visibility_tag_t get_elf_visibility_from_string(const char *string)
+{
+       if (streq(string, "default")) {
+               return ELF_VISIBILITY_DEFAULT;
+       } else if (streq(string, "hidden")) {
+               return ELF_VISIBILITY_HIDDEN;
+       } else if (streq(string, "internal")) {
+               return ELF_VISIBILITY_INTERNAL;
+       } else if (streq(string, "protected")) {
+               return ELF_VISIBILITY_PROTECTED;
+       } else {
+               return ELF_VISIBILITY_ERROR;
+       }
+}
index 1af1ce9..364e644 100644 (file)
@@ -95,6 +95,14 @@ typedef enum decl_modifier_t {
        DM_WEAK              = 1 << 27,
 } decl_modifier_t;
 
+typedef enum elf_visibility_tag_t {
+       ELF_VISIBILITY_DEFAULT,
+       ELF_VISIBILITY_HIDDEN,
+       ELF_VISIBILITY_INTERNAL,
+       ELF_VISIBILITY_PROTECTED,
+       ELF_VISIBILITY_ERROR
+} elf_visibility_tag_t;
+
 /**
  * A scope containing entities.
  */
@@ -212,13 +220,14 @@ struct compound_member_t {
 
 struct variable_t {
        declaration_t     base;
-       bool              thread_local  : 1;  /**< GCC __thread */
-       bool              restricta     : 1;
-       bool              deprecated    : 1;
-       bool              noalias       : 1;
+       bool              thread_local   : 1;  /**< GCC __thread */
+       bool              restricta      : 1;
+       bool              deprecated     : 1;
+       bool              noalias        : 1;
 
-       bool              address_taken : 1;  /**< Set if the address of this declaration was taken. */
-       bool              read          : 1;
+       bool              address_taken  : 1;  /**< Set if the address of this declaration was taken. */
+       bool              read           : 1;
+       unsigned          elf_visibility : 2;
 
        initializer_t    *initializer;
 
@@ -244,10 +253,11 @@ struct parameter_t {
 
 struct function_t {
        declaration_t  base;
-       bool           is_inline     : 1;
+       bool           is_inline      : 1;
 
-       bool           need_closure  : 1;  /**< Inner function needs closure. */
-       bool           goto_to_outer : 1;  /**< Inner function has goto to outer function. */
+       bool           need_closure   : 1;  /**< Inner function needs closure. */
+       bool           goto_to_outer  : 1;  /**< Inner function has goto to outer function. */
+       unsigned       elf_visibility : 2;
 
        builtin_kind_t btk;
        scope_t        parameters;
@@ -296,4 +306,6 @@ const char *get_entity_kind_name(entity_kind_t kind);
 
 entity_t *allocate_entity_zero(entity_kind_t kind);
 
+elf_visibility_tag_t get_elf_visibility_from_string(const char *string);
+
 #endif
diff --git a/main.c b/main.c
index c31427f..a638a1a 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1026,9 +1026,19 @@ int main(int argc, char **argv)
                                        select_input_encoding(encoding);
                                } else if (strstart(orig_opt, "align-loops=") ||
                                           strstart(orig_opt, "align-jumps=") ||
-                                          strstart(orig_opt, "visibility=")  ||
                                           strstart(orig_opt, "align-functions=")) {
                                        fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
+                               } else if (strstart(orig_opt, "visibility=")) {
+                                       const char *arg = strchr(orig_opt, '=')+1;
+                                       elf_visibility_tag_t visibility
+                                               = get_elf_visibility_from_string(arg);
+                                       if (visibility == ELF_VISIBILITY_ERROR) {
+                                               fprintf(stderr, "invalid visibility '%s' specified\n",
+                                                       arg);
+                                               argument_errors = true;
+                                       } else {
+                                               set_default_visibility(visibility);
+                                       }
                                } else if (strstart(orig_opt, "message-length=")) {
                                        /* ignore: would only affect error message format */
                                } else {
index a420d68..39e63ce 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -108,6 +108,7 @@ static bool                 in_gcc_extension  = false;
 static struct obstack       temp_obst;
 static entity_t            *anonymous_entity;
 static declaration_t      **incomplete_arrays;
+static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 
 
 #define PUSH_PARENT(stmt)                          \
@@ -3940,8 +3941,9 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                } else if (is_type_function(type)) {
                        entity = allocate_entity_zero(ENTITY_FUNCTION);
 
-                       entity->function.is_inline  = specifiers->is_inline;
-                       entity->function.parameters = env.parameters;
+                       entity->function.is_inline      = specifiers->is_inline;
+                       entity->function.elf_visibility = default_visibility;
+                       entity->function.parameters     = env.parameters;
 
                        if (env.symbol != NULL) {
                                /* this needs fixes for C++ */
@@ -3959,7 +3961,8 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                } else {
                        entity = allocate_entity_zero(ENTITY_VARIABLE);
 
-                       entity->variable.thread_local = specifiers->thread_local;
+                       entity->variable.elf_visibility = default_visibility;
+                       entity->variable.thread_local   = specifiers->thread_local;
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
@@ -10829,6 +10832,11 @@ static void parse_translation_unit(void)
        }
 }
 
+void set_default_visibility(elf_visibility_tag_t visibility)
+{
+       default_visibility = visibility;
+}
+
 /**
  * Parse the input.
  *
index f402908..6ccf6e4 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -21,6 +21,7 @@
 #define PARSER_H
 
 #include "ast.h"
+#include "entity_t.h"
 #include "type.h"
 
 typedef struct environment_entry_t environment_entry_t;
@@ -57,4 +58,7 @@ void prepare_main_collect2(entity_t *entity);
 
 entity_t *record_entity(entity_t *entity, bool is_definition);
 
+/** set default elf visbility */
+void set_default_visibility(elf_visibility_tag_t visibility);
+
 #endif
index e99761b..6387217 100644 (file)
@@ -538,6 +538,8 @@ void write_jna_decls(FILE *output, const translation_unit_t *unit)
                const char *input_name = entity->base.source_position.input_name;
                if (is_system_header(input_name))
                        continue;
+               if (entity->function.elf_visibility != ELF_VISIBILITY_DEFAULT)
+                       continue;
                if (output_limits != NULL) {
                        bool in_limits = false;
                        for (output_limit *limit = output_limits; limit != NULL;