Skip to content

Commit 446726e

Browse files
committed
Fully support aarch64 ABI's va_list struct
aarch64 ABI (section 7.1.4) mandates that va_list is a struct with particular members. The C library model was fixed in #8366, but we didn't yet implement the struct type support in goto conversion.
1 parent 433ef5b commit 446726e

6 files changed

+77
-17
lines changed

src/ansi-c/ansi_c_internal_additions.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,23 @@ void ansi_c_internal_additions(std::string &code, bool support_float16_type)
286286
code+="typedef signed __int128 __int128_t;\n"
287287
"typedef unsigned __int128 __uint128_t;\n";
288288
}
289+
290+
if(
291+
config.ansi_c.arch == "arm64" &&
292+
config.ansi_c.os != configt::ansi_ct::ost::OS_MACOS)
293+
{
294+
code += "typedef struct __va_list {";
295+
code += "void *__stack;";
296+
code += "void *__gr_top;";
297+
code += "void *__vr_top;";
298+
code += "int __gr_offs;";
299+
code += "int __vr_offs;";
300+
code += " } __builtin_va_list;\n";
301+
}
302+
else
303+
{
304+
code += "typedef void ** __builtin_va_list;\n";
305+
}
289306
}
290307

291308
// this is Visual C/C++ only

src/ansi-c/c_typecheck_expr.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -541,12 +541,20 @@ void c_typecheck_baset::typecheck_expr_builtin_va_arg(exprt &expr)
541541
typet arg_type=expr.type();
542542
typecheck_type(arg_type);
543543

544+
const symbolt *symbol_ptr;
545+
if(lookup("__builtin_va_list", symbol_ptr))
546+
{
547+
error().source_location = expr.source_location();
548+
error() << "failed to find typedef name __builtin_va_list" << eom;
549+
throw 0;
550+
}
551+
544552
const code_typet new_type(
545-
{code_typet::parametert(pointer_type(void_type()))}, std::move(arg_type));
553+
{code_typet::parametert(symbol_ptr->type)}, std::move(arg_type));
546554

547555
exprt arg = to_unary_expr(expr).op();
548556

549-
implicit_typecast(arg, pointer_type(void_type()));
557+
implicit_typecast(arg, new_type.parameters().front().type());
550558

551559
symbol_exprt function(ID_gcc_builtin_va_arg, new_type);
552560
function.add_source_location() = expr.source_location();

src/ansi-c/compiler_headers/gcc_builtin_headers_generic.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
// stdarg
33
void* __builtin_apply_args();
44
void* __builtin_apply(void (*)(), void*, __CPROVER_size_t);
5-
void __builtin_ms_va_end(void *ap);
6-
void __builtin_ms_va_start(void *ap, ...);
5+
void __builtin_ms_va_end(__builtin_ms_va_list ap);
6+
void __builtin_ms_va_start(__builtin_ms_va_list ap, ...);
77
void* __builtin_next_arg();
88
int __builtin_va_arg_pack();
99
int __builtin_va_arg_pack_len();
1010
void __builtin_va_copy(__builtin_va_list dest, __builtin_va_list src);
11-
void __builtin_va_end(void *ap);
12-
void __builtin_va_start(void *ap, ...);
11+
void __builtin_va_end(__builtin_va_list ap);
12+
void __builtin_va_start(__builtin_va_list ap, ...);
1313

1414
// stdlib
1515
void __builtin__Exit(int);

src/ansi-c/compiler_headers/gcc_builtin_headers_types.h

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// clang-format off
2-
typedef void ** __builtin_va_list;
32
typedef void ** __builtin_ms_va_list;
43

54
typedef int __gcc_m64 __attribute__ ((__vector_size__ (8), __may_alias__));

src/ansi-c/goto-conversion/builtin_functions.cpp

+29-10
Original file line numberDiff line numberDiff line change
@@ -593,8 +593,20 @@ void goto_convertt::do_array_op(
593593
copy(array_op_statement, OTHER, dest);
594594
}
595595

596-
exprt make_va_list(const exprt &expr)
596+
static exprt make_va_list(const exprt &expr, const namespacet &ns)
597597
{
598+
if(
599+
auto struct_tag_type = type_try_dynamic_cast<struct_tag_typet>(expr.type()))
600+
{
601+
// aarch64 ABI mandates that va_list has struct type with member names as
602+
// specified
603+
const auto &components = ns.follow_tag(*struct_tag_type).components();
604+
DATA_INVARIANT(
605+
components.size() == 5,
606+
"va_list struct type expected to have 5 components");
607+
return member_exprt{expr, components.front()};
608+
}
609+
598610
exprt result = skip_typecast(expr);
599611

600612
// if it's an address of an lvalue, we take that
@@ -1296,14 +1308,15 @@ void goto_convertt::do_function_call_symbol(
12961308
throw 0;
12971309
}
12981310

1299-
exprt list_arg = make_va_list(arguments[0]);
1311+
exprt list_arg = make_va_list(arguments[0], ns);
1312+
const bool va_list_is_void_ptr =
1313+
list_arg.type().id() == ID_pointer &&
1314+
to_pointer_type(list_arg.type()).base_type().id() == ID_empty;
13001315

13011316
if(lhs.is_not_nil())
13021317
{
13031318
exprt list_arg_cast = list_arg;
1304-
if(
1305-
list_arg.type().id() == ID_pointer &&
1306-
to_pointer_type(list_arg.type()).base_type().id() == ID_empty)
1319+
if(va_list_is_void_ptr)
13071320
{
13081321
list_arg_cast =
13091322
typecast_exprt{list_arg, pointer_type(pointer_type(empty_typet{}))};
@@ -1317,8 +1330,14 @@ void goto_convertt::do_function_call_symbol(
13171330
goto_programt::make_assignment(lhs, rhs, function.source_location()));
13181331
}
13191332

1320-
code_assignt assign{
1321-
list_arg, plus_exprt{list_arg, from_integer(1, pointer_diff_type())}};
1333+
exprt list_arg_ptr_arithmetic = typecast_exprt::conditional_cast(
1334+
plus_exprt{
1335+
(va_list_is_void_ptr
1336+
? typecast_exprt{list_arg, pointer_type(pointer_type(empty_typet{}))}
1337+
: list_arg),
1338+
from_integer(1, pointer_diff_type())},
1339+
list_arg.type());
1340+
code_assignt assign{list_arg, std::move(list_arg_ptr_arithmetic)};
13221341
assign.rhs().set(
13231342
ID_C_va_arg_type, to_code_type(function.type()).return_type());
13241343
dest.add(goto_programt::make_assignment(
@@ -1333,7 +1352,7 @@ void goto_convertt::do_function_call_symbol(
13331352
throw 0;
13341353
}
13351354

1336-
exprt dest_expr = make_va_list(arguments[0]);
1355+
exprt dest_expr = make_va_list(arguments[0], ns);
13371356
const typecast_exprt src_expr(arguments[1], dest_expr.type());
13381357

13391358
if(!is_assignable(dest_expr))
@@ -1357,7 +1376,7 @@ void goto_convertt::do_function_call_symbol(
13571376
throw 0;
13581377
}
13591378

1360-
exprt dest_expr = make_va_list(arguments[0]);
1379+
exprt dest_expr = make_va_list(arguments[0], ns);
13611380

13621381
if(!is_assignable(dest_expr))
13631382
{
@@ -1392,7 +1411,7 @@ void goto_convertt::do_function_call_symbol(
13921411
throw 0;
13931412
}
13941413

1395-
exprt dest_expr = make_va_list(arguments[0]);
1414+
exprt dest_expr = make_va_list(arguments[0], ns);
13961415

13971416
if(!is_assignable(dest_expr))
13981417
{

src/cpp/cpp_internal_additions.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,23 @@ void cpp_internal_additions(std::ostream &out)
155155
out << "typedef signed __int128 __int128_t;" << '\n';
156156
out << "typedef unsigned __int128 __uint128_t;" << '\n';
157157
}
158+
159+
if(
160+
config.ansi_c.arch == "arm64" &&
161+
config.ansi_c.os != configt::ansi_ct::ost::OS_MACOS)
162+
{
163+
code += "typedef struct __va_list {";
164+
code += "void *__stack;";
165+
code += "void *__gr_top;";
166+
code += "void *__vr_top;";
167+
code += "int __gr_offs;";
168+
code += "int __vr_offs;";
169+
code += " } __builtin_va_list;\n";
170+
}
171+
else
172+
{
173+
code += "typedef void ** __builtin_va_list;\n";
174+
}
158175
}
159176

160177
// this is Visual C/C++ only

0 commit comments

Comments
 (0)