Currently only used for jna export though.
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;
}
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);
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;
}
#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)
{
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;
+ }
+}
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.
*/
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;
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;
entity_t *allocate_entity_zero(entity_kind_t kind);
+elf_visibility_tag_t get_elf_visibility_from_string(const char *string);
+
#endif
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 {
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) \
} 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++ */
} 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)) {
}
}
+void set_default_visibility(elf_visibility_tag_t visibility)
+{
+ default_visibility = visibility;
+}
+
/**
* Parse the input.
*
#define PARSER_H
#include "ast.h"
+#include "entity_t.h"
#include "type.h"
typedef struct environment_entry_t environment_entry_t;
entity_t *record_entity(entity_t *entity, bool is_definition);
+/** set default elf visbility */
+void set_default_visibility(elf_visibility_tag_t visibility);
+
#endif
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;