Skip to content

Commit 090790a

Browse files
committed
Interpret GCC's attribute __used__
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.
1 parent 7985716 commit 090790a

File tree

11 files changed

+51
-2
lines changed

11 files changed

+51
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifdef __GNUC__
2+
static int foo __attribute__((used)) = 42;
3+
#else
4+
int foo = 42;
5+
#endif
6+
7+
int main()
8+
{
9+
return 0;
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^[[:space:]]*foo = 42;$
7+
--
8+
^warning: ignoring
9+
^CONVERSION ERROR$

src/ansi-c/ansi_c_convert_type.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ void ansi_c_convert_typet::read_rec(const typet &type)
169169
c_storage_spec.is_register=true;
170170
else if(type.id()==ID_weak)
171171
c_storage_spec.is_weak=true;
172+
else if(type.id() == ID_used)
173+
c_storage_spec.is_used = true;
172174
else if(type.id()==ID_auto)
173175
{
174176
// ignore

src/ansi-c/ansi_c_declaration.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,10 @@ void ansi_c_declarationt::to_symbol(
165165
else if(get_is_extern()) // traditional GCC
166166
symbol.is_file_local=true;
167167
}
168+
169+
// GCC __attribute__((__used__)) - do not treat those as file-local
170+
if(get_is_used())
171+
symbol.is_file_local = false;
168172
}
169173
}
170174
else // non-function
@@ -181,7 +185,7 @@ void ansi_c_declarationt::to_symbol(
181185
symbol.is_file_local=
182186
symbol.is_macro ||
183187
(!get_is_global() && !get_is_extern()) ||
184-
(get_is_global() && get_is_static()) ||
188+
(get_is_global() && get_is_static() && !get_is_used()) ||
185189
symbol.is_parameter;
186190
}
187191
}

src/ansi-c/ansi_c_declaration.h

+10
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,16 @@ class ansi_c_declarationt:public exprt
195195
set(ID_is_weak, is_weak);
196196
}
197197

198+
bool get_is_used() const
199+
{
200+
return get_bool(ID_is_used);
201+
}
202+
203+
void set_is_used(bool is_used)
204+
{
205+
set(ID_is_used, is_used);
206+
}
207+
198208
void to_symbol(
199209
const ansi_c_declaratort &,
200210
symbolt &symbol) const;

src/ansi-c/c_storage_spec.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ void c_storage_spect::read(const typet &type)
3232
is_register=true;
3333
else if(type.id()==ID_weak)
3434
is_weak=true;
35+
else if(type.id() == ID_used)
36+
is_used = true;
3537
else if(type.id()==ID_auto)
3638
{
3739
// ignore

src/ansi-c/c_storage_spec.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ class c_storage_spect
3535
is_register=false;
3636
is_inline=false;
3737
is_weak=false;
38+
is_used = false;
3839
alias.clear();
3940
asm_label.clear();
4041
section.clear();
4142
}
4243

4344
bool is_typedef, is_extern, is_static, is_register,
44-
is_inline, is_thread_local, is_weak;
45+
is_inline, is_thread_local, is_weak, is_used;
4546

4647
// __attribute__((alias("foo")))
4748
irep_idt alias;
@@ -59,6 +60,7 @@ class c_storage_spect
5960
is_thread_local==other.is_thread_local &&
6061
is_inline==other.is_inline &&
6162
is_weak==other.is_weak &&
63+
is_used == other.is_used &&
6264
alias==other.alias &&
6365
asm_label==other.asm_label &&
6466
section==other.section;
@@ -78,6 +80,7 @@ class c_storage_spect
7880
is_inline |=other.is_inline;
7981
is_thread_local |=other.is_thread_local;
8082
is_weak |=other.is_weak;
83+
is_used |=other.is_used;
8184
if(alias.empty())
8285
alias=other.alias;
8386
if(asm_label.empty())

src/ansi-c/c_typecheck_base.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ void c_typecheck_baset::typecheck_declaration(
688688
declaration.set_is_register(full_spec.is_register);
689689
declaration.set_is_typedef(full_spec.is_typedef);
690690
declaration.set_is_weak(full_spec.is_weak);
691+
declaration.set_is_used(full_spec.is_used);
691692

692693
symbolt symbol;
693694
declaration.to_symbol(*d_it, symbol);

src/ansi-c/parser.y

+3
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ extern char *yyansi_ctext;
149149
%token TOK_GCC_ATTRIBUTE_CONSTRUCTOR "constructor"
150150
%token TOK_GCC_ATTRIBUTE_DESTRUCTOR "destructor"
151151
%token TOK_GCC_ATTRIBUTE_FALLTHROUGH "fallthrough"
152+
%token TOK_GCC_ATTRIBUTE_USED "used"
152153
%token TOK_GCC_LABEL "__label__"
153154
%token TOK_MSC_ASM "__asm"
154155
%token TOK_MSC_BASED "__based"
@@ -1544,6 +1545,8 @@ gcc_type_attribute:
15441545
{ $$=$1; set($$, ID_constructor); }
15451546
| TOK_GCC_ATTRIBUTE_DESTRUCTOR
15461547
{ $$=$1; set($$, ID_destructor); }
1548+
| TOK_GCC_ATTRIBUTE_USED
1549+
{ $$=$1; set($$, ID_used); }
15471550
;
15481551

15491552
gcc_attribute:

src/ansi-c/scanner.l

+3
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,9 @@ __decltype { if(PARSER.cpp98 &&
15821582

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

1585+
"used" |
1586+
"__used__" { BEGIN(GCC_ATTRIBUTE3); loc(); return TOK_GCC_ATTRIBUTE_USED; }
1587+
15851588
{ws} { /* ignore */ }
15861589
{newline} { /* ignore */ }
15871590
{identifier} { BEGIN(GCC_ATTRIBUTE4); }

src/util/irep_ids.def

+2
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,8 @@ IREP_ID_ONE(noreturn)
561561
IREP_ID_TWO(C_noreturn, #noreturn)
562562
IREP_ID_ONE(weak)
563563
IREP_ID_ONE(is_weak)
564+
IREP_ID_ONE(used)
565+
IREP_ID_ONE(is_used)
564566
IREP_ID_TWO(C_spec_loop_invariant, #spec_loop_invariant)
565567
IREP_ID_TWO(C_spec_requires, #spec_requires)
566568
IREP_ID_TWO(C_spec_ensures, #spec_ensures)

0 commit comments

Comments
 (0)