Skip to content

Commit 3fc6fd5

Browse files
committed
Fix parameter handling in remove_asmt::{gcc,msc}_asm_function_call
We did not have any tests that exercised the parameter-requiring cases of inline assembler. Enabling these uncovered that we failed to construct the correct types. In the MSVC case we did not have any support for parameters at all.
1 parent 8f4a19a commit 3fc6fd5

File tree

7 files changed

+139
-15
lines changed

7 files changed

+139
-15
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
volatile int turn;
2+
int x;
3+
volatile int flag1 = 0, flag2 = 0;
4+
5+
void *thr1(void *arg)
6+
{
7+
flag1 = 1;
8+
turn = 1;
9+
__asm { mfence; }
10+
__CPROVER_assume(!(flag2 == 1 && turn == 1));
11+
x = 0;
12+
__CPROVER_assert(x <= 0, "");
13+
flag1 = 0;
14+
}
15+
16+
void *thr2(void *arg)
17+
{
18+
flag2 = 1;
19+
turn = 0;
20+
__asm { mfence; }
21+
__CPROVER_assume(!(flag1 == 1 && turn == 0));
22+
x = 1;
23+
__CPROVER_assert(x >= 1, "");
24+
flag2 = 0;
25+
}
26+
27+
int main()
28+
{
29+
__CPROVER_ASYNC_1:
30+
thr1(0);
31+
thr2(0);
32+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
msvc.c
3+
--mm tso --winx64
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
This is the same test as main.c/test.desc, but now using Visual Studio inline
11+
ASM syntax.
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
#include <assert.h>
2-
#include <x86_assembler.h>
2+
#include <fenv.h>
33

44
int main()
55
{
6-
__asm_fstcw();
7-
assert(0);
8-
return 0;
6+
unsigned short cw;
7+
#ifdef __GNUC__
8+
__asm__("fstcw %0" : "=m"(cw));
9+
#else
10+
__asm { fstcw cw; }
11+
#endif
12+
assert((cw & 0xc00) == 0);
13+
fesetround(FE_UPWARD);
14+
#ifdef __GNUC__
15+
__asm__("fstcw %0" : "=m"(cw));
16+
#else
17+
__asm { fstcw cw; }
18+
#endif
19+
assert((cw & 0xc00) == 0x800);
920
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int main()
2+
{
3+
unsigned short cw;
4+
__asm { fstcw cw; }
5+
__CPROVER_assert((cw & 0xc00) == 0, "default rounding mode");
6+
// fesetround(FE_UPWARD);
7+
__CPROVER_rounding_mode = 2;
8+
__asm { fstcw cw; }
9+
__CPROVER_assert((cw & 0xc00) == 0x800, "round upwards");
10+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
msvc.c
3+
--pointer-check --bounds-check --winx64
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
This is the same test as main.c/test.desc, but now using Visual Studio inline
11+
ASM syntax.

regression/cbmc-library/__asm_fstcw-01/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33
--pointer-check --bounds-check
44
^EXIT=0$

src/assembler/remove_asm.cpp

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Date: December 2014
1717

1818
#include <util/c_types.h>
1919
#include <util/pointer_expr.h>
20+
#include <util/prefix.h>
21+
#include <util/range.h>
2022
#include <util/std_code.h>
2123
#include <util/string_constant.h>
2224

@@ -36,22 +38,26 @@ class remove_asmt
3638
void operator()()
3739
{
3840
for(auto &f : goto_functions.function_map)
39-
process_function(f.second);
41+
process_function(f.first, f.second);
4042
}
4143

4244
protected:
4345
symbol_tablet &symbol_table;
4446
goto_functionst &goto_functions;
4547

46-
void process_function(goto_functionst::goto_functiont &);
48+
void process_function(const irep_idt &, goto_functionst::goto_functiont &);
4749

4850
void process_instruction(
51+
const irep_idt &function_id,
4952
goto_programt::instructiont &instruction,
5053
goto_programt &dest);
5154

5255
void process_instruction_gcc(const code_asm_gcct &, goto_programt &dest);
5356

54-
void process_instruction_msc(const code_asmt &, goto_programt &dest);
57+
void process_instruction_msc(
58+
const irep_idt &,
59+
const code_asmt &,
60+
goto_programt &dest);
5561

5662
void gcc_asm_function_call(
5763
const irep_idt &function_base_name,
@@ -60,6 +66,7 @@ class remove_asmt
6066

6167
void msc_asm_function_call(
6268
const irep_idt &function_base_name,
69+
const exprt::operandst &operands,
6370
const code_asmt &code,
6471
goto_programt &dest);
6572
};
@@ -102,7 +109,10 @@ void remove_asmt::gcc_asm_function_call(
102109
}
103110
}
104111

105-
code_typet fkt_type({}, empty_typet());
112+
code_typet fkt_type{
113+
code_typet::parameterst{
114+
arguments.size(), code_typet::parametert{void_pointer}},
115+
empty_typet()};
106116

107117
symbol_exprt fkt(function_identifier, fkt_type);
108118

@@ -138,23 +148,33 @@ void remove_asmt::gcc_asm_function_call(
138148
/// assembly statement
139149
///
140150
/// \param function_base_name: Name of the function to call
151+
/// \param operands: Arguments to be passed to function
141152
/// \param code: msc-style inline assembly statement to translate to function
142153
/// call
143154
/// \param dest: Goto program to append the function call to
144155
void remove_asmt::msc_asm_function_call(
145156
const irep_idt &function_base_name,
157+
const exprt::operandst &operands,
146158
const code_asmt &code,
147159
goto_programt &dest)
148160
{
149161
irep_idt function_identifier = function_base_name;
150162

163+
code_function_callt::argumentst arguments;
164+
151165
const typet void_pointer = pointer_type(empty_typet());
152166

153-
code_typet fkt_type({}, empty_typet());
167+
for(const auto &op : operands)
168+
arguments.push_back(typecast_exprt::conditional_cast(op, void_pointer));
169+
170+
code_typet fkt_type{
171+
code_typet::parameterst{
172+
arguments.size(), code_typet::parametert{void_pointer}},
173+
empty_typet()};
154174

155175
symbol_exprt fkt(function_identifier, fkt_type);
156176

157-
code_function_callt function_call(fkt);
177+
code_function_callt function_call(std::move(fkt), std::move(arguments));
158178

159179
dest.add(
160180
goto_programt::make_function_call(function_call, code.source_location()));
@@ -185,10 +205,12 @@ void remove_asmt::msc_asm_function_call(
185205
/// Translates the given inline assembly code (which must be in either gcc or
186206
/// msc style) to non-assembly goto program instructions
187207
///
208+
/// \param function_id: Name of function being processed
188209
/// \param instruction: The goto program instruction containing the inline
189210
/// assembly statements
190211
/// \param dest: The goto program to append the new instructions to
191212
void remove_asmt::process_instruction(
213+
const irep_idt &function_id,
192214
goto_programt::instructiont &instruction,
193215
goto_programt &dest)
194216
{
@@ -199,7 +221,7 @@ void remove_asmt::process_instruction(
199221
if(flavor == ID_gcc)
200222
process_instruction_gcc(to_code_asm_gcc(code), dest);
201223
else if(flavor == ID_msc)
202-
process_instruction_msc(code, dest);
224+
process_instruction_msc(function_id, code, dest);
203225
else
204226
DATA_INVARIANT(false, "unexpected assembler flavor");
205227
}
@@ -376,9 +398,11 @@ void remove_asmt::process_instruction_gcc(
376398
/// Translates the given inline assembly code (in msc style) to non-assembly
377399
/// goto program instructions
378400
///
401+
/// \param function_id: Name of function being processed
379402
/// \param code: The inline assembly code statement to translate
380403
/// \param dest: The goto program to append the new instructions to
381404
void remove_asmt::process_instruction_msc(
405+
const irep_idt &function_id,
382406
const code_asmt &code,
383407
goto_programt &dest)
384408
{
@@ -450,12 +474,35 @@ void remove_asmt::process_instruction_msc(
450474

451475
if(command == "fstcw" || command == "fnstcw" || command == "fldcw") // x86
452476
{
453-
msc_asm_function_call("__asm_" + id2string(command), code, tmp_dest);
477+
exprt::operandst args{null_pointer_exprt{pointer_type(empty_typet{})}};
478+
// try to typecheck the argument
479+
if(pos != instruction.size() && instruction[pos].id() == ID_symbol)
480+
{
481+
const irep_idt &name = instruction[pos].get(ID_identifier);
482+
for(const auto &entry : equal_range(symbol_table.symbol_base_map, name))
483+
{
484+
// global scope symbol, don't replace a local one
485+
if(entry.second == name && args[0].id() != ID_address_of)
486+
{
487+
args[0] =
488+
address_of_exprt{symbol_table.lookup_ref(name).symbol_expr()};
489+
}
490+
// parameter or symbol in local scope
491+
else if(has_prefix(
492+
id2string(entry.second), id2string(function_id) + "::"))
493+
{
494+
args[0] = address_of_exprt{
495+
symbol_table.lookup_ref(entry.second).symbol_expr()};
496+
}
497+
}
498+
}
499+
msc_asm_function_call(
500+
"__asm_" + id2string(command), args, code, tmp_dest);
454501
}
455502
else if(
456503
command == "mfence" || command == "lfence" || command == "sfence") // x86
457504
{
458-
msc_asm_function_call("__asm_" + id2string(command), code, tmp_dest);
505+
msc_asm_function_call("__asm_" + id2string(command), {}, code, tmp_dest);
459506
}
460507
else
461508
unknown = true; // give up
@@ -479,8 +526,10 @@ void remove_asmt::process_instruction_msc(
479526
/// Replaces inline assembly instructions in the goto function by non-assembly
480527
/// goto program instructions
481528
///
529+
/// \param function_id: Name of function being processed
482530
/// \param goto_function: The goto function
483531
void remove_asmt::process_function(
532+
const irep_idt &function_id,
484533
goto_functionst::goto_functiont &goto_function)
485534
{
486535
bool did_something = false;
@@ -490,7 +539,7 @@ void remove_asmt::process_function(
490539
if(it->is_other() && it->get_other().get_statement() == ID_asm)
491540
{
492541
goto_programt tmp_dest;
493-
process_instruction(*it, tmp_dest);
542+
process_instruction(function_id, *it, tmp_dest);
494543
it->turn_into_skip();
495544
did_something = true;
496545

0 commit comments

Comments
 (0)