Skip to content

Commit

Permalink
Interpret GCC's attribute __used__
Browse files Browse the repository at this point in the history
The Linux kernel marks various otherwise static (i.e., file-local)
symbols using __attribute__((__used__)) to retain them. Not interpreting
this attribute makes linking wrongly discard code and objects.
  • Loading branch information
tautschnig committed Jun 4, 2018
1 parent 7985716 commit 090790a
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 2 deletions.
10 changes: 10 additions & 0 deletions regression/goto-instrument/gcc_attribute_used1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifdef __GNUC__
static int foo __attribute__((used)) = 42;
#else
int foo = 42;
#endif

int main()
{
return 0;
}
9 changes: 9 additions & 0 deletions regression/goto-instrument/gcc_attribute_used1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CORE
main.c

^EXIT=0$
^SIGNAL=0$
^[[:space:]]*foo = 42;$
--
^warning: ignoring
^CONVERSION ERROR$
2 changes: 2 additions & 0 deletions src/ansi-c/ansi_c_convert_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ void ansi_c_convert_typet::read_rec(const typet &type)
c_storage_spec.is_register=true;
else if(type.id()==ID_weak)
c_storage_spec.is_weak=true;
else if(type.id() == ID_used)
c_storage_spec.is_used = true;
else if(type.id()==ID_auto)
{
// ignore
Expand Down
6 changes: 5 additions & 1 deletion src/ansi-c/ansi_c_declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ void ansi_c_declarationt::to_symbol(
else if(get_is_extern()) // traditional GCC
symbol.is_file_local=true;
}

// GCC __attribute__((__used__)) - do not treat those as file-local
if(get_is_used())
symbol.is_file_local = false;
}
}
else // non-function
Expand All @@ -181,7 +185,7 @@ void ansi_c_declarationt::to_symbol(
symbol.is_file_local=
symbol.is_macro ||
(!get_is_global() && !get_is_extern()) ||
(get_is_global() && get_is_static()) ||
(get_is_global() && get_is_static() && !get_is_used()) ||
symbol.is_parameter;
}
}
10 changes: 10 additions & 0 deletions src/ansi-c/ansi_c_declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,16 @@ class ansi_c_declarationt:public exprt
set(ID_is_weak, is_weak);
}

bool get_is_used() const
{
return get_bool(ID_is_used);
}

void set_is_used(bool is_used)
{
set(ID_is_used, is_used);
}

void to_symbol(
const ansi_c_declaratort &,
symbolt &symbol) const;
Expand Down
2 changes: 2 additions & 0 deletions src/ansi-c/c_storage_spec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ void c_storage_spect::read(const typet &type)
is_register=true;
else if(type.id()==ID_weak)
is_weak=true;
else if(type.id() == ID_used)
is_used = true;
else if(type.id()==ID_auto)
{
// ignore
Expand Down
5 changes: 4 additions & 1 deletion src/ansi-c/c_storage_spec.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ class c_storage_spect
is_register=false;
is_inline=false;
is_weak=false;
is_used = false;
alias.clear();
asm_label.clear();
section.clear();
}

bool is_typedef, is_extern, is_static, is_register,
is_inline, is_thread_local, is_weak;
is_inline, is_thread_local, is_weak, is_used;

// __attribute__((alias("foo")))
irep_idt alias;
Expand All @@ -59,6 +60,7 @@ class c_storage_spect
is_thread_local==other.is_thread_local &&
is_inline==other.is_inline &&
is_weak==other.is_weak &&
is_used == other.is_used &&
alias==other.alias &&
asm_label==other.asm_label &&
section==other.section;
Expand All @@ -78,6 +80,7 @@ class c_storage_spect
is_inline |=other.is_inline;
is_thread_local |=other.is_thread_local;
is_weak |=other.is_weak;
is_used |=other.is_used;
if(alias.empty())
alias=other.alias;
if(asm_label.empty())
Expand Down
1 change: 1 addition & 0 deletions src/ansi-c/c_typecheck_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,7 @@ void c_typecheck_baset::typecheck_declaration(
declaration.set_is_register(full_spec.is_register);
declaration.set_is_typedef(full_spec.is_typedef);
declaration.set_is_weak(full_spec.is_weak);
declaration.set_is_used(full_spec.is_used);

symbolt symbol;
declaration.to_symbol(*d_it, symbol);
Expand Down
3 changes: 3 additions & 0 deletions src/ansi-c/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ extern char *yyansi_ctext;
%token TOK_GCC_ATTRIBUTE_CONSTRUCTOR "constructor"
%token TOK_GCC_ATTRIBUTE_DESTRUCTOR "destructor"
%token TOK_GCC_ATTRIBUTE_FALLTHROUGH "fallthrough"
%token TOK_GCC_ATTRIBUTE_USED "used"
%token TOK_GCC_LABEL "__label__"
%token TOK_MSC_ASM "__asm"
%token TOK_MSC_BASED "__based"
Expand Down Expand Up @@ -1544,6 +1545,8 @@ gcc_type_attribute:
{ $$=$1; set($$, ID_constructor); }
| TOK_GCC_ATTRIBUTE_DESTRUCTOR
{ $$=$1; set($$, ID_destructor); }
| TOK_GCC_ATTRIBUTE_USED
{ $$=$1; set($$, ID_used); }
;

gcc_attribute:
Expand Down
3 changes: 3 additions & 0 deletions src/ansi-c/scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,9 @@ __decltype { if(PARSER.cpp98 &&

"fallthrough" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_FALLTHROUGH; }

"used" |
"__used__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_USED; }

{ws} { /* ignore */ }
{newline} { /* ignore */ }
{identifier} { BEGIN(GCC_ATTRIBUTE4); }
Expand Down
2 changes: 2 additions & 0 deletions src/util/irep_ids.def
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,8 @@ IREP_ID_ONE(noreturn)
IREP_ID_TWO(C_noreturn, #noreturn)
IREP_ID_ONE(weak)
IREP_ID_ONE(is_weak)
IREP_ID_ONE(used)
IREP_ID_ONE(is_used)
IREP_ID_TWO(C_spec_loop_invariant, #spec_loop_invariant)
IREP_ID_TWO(C_spec_requires, #spec_requires)
IREP_ID_TWO(C_spec_ensures, #spec_ensures)
Expand Down

0 comments on commit 090790a

Please sign in to comment.