我正在为我的应用程序使用MPLAB XC16 C编译器。如果我使用machdep x86_16,Frama-C正常工作。例如,我可以用这种方式发布Frama-C:
$ frama-c-gui machdep x86_16 -cpp-command 'C:\\"Program Files (x86)"\\Microchip\\xc16\\v1.26\\bin\\xc16-gcc.exe -E' -no-cpp-gnu-like D:\\project\\*.c
但是machdep x86_16并不完全符合XC16。所以我想定制machdep。
在the instructions之后,我创建了包含以下内容的文件machdep_xc16.ml:
open Cil_types
let xc16 =
{
version = "dsPIC33F";
compiler = "XC16"; (* Compiler being used. *)
sizeof_short = 2; (* Size of "short" *)
sizeof_int = 2; (* Size of "int" *)
sizeof_long = 4; (* Size of "long" *)
sizeof_longlong = 8; (* Size of "long long" *)
sizeof_ptr = 2; (* Size of pointers *)
sizeof_float = 4; (* Size of "float" *)
sizeof_double = 4; (* Size of "double" *)
sizeof_longdouble = 8; (* Size of "long double" *)
sizeof_void = 0; (* Size of "void" *)
sizeof_fun = 0; (* Size of function *)
size_t = "unsigned int"; (* Type of "sizeof(T)" *)
wchar_t = "unsigned short"; (* Type of "wchar_t" *)
ptrdiff_t = "int"; (* Type of "ptrdiff_t" *)
alignof_short = 2; (* Alignment of "short" *)
alignof_int = 2; (* Alignment of "int" *)
alignof_long = 2; (* Alignment of "long" *)
alignof_longlong = 2; (* Alignment of "long long" *)
alignof_ptr = 2; (* Alignment of pointers *)
alignof_float = 2; (* Alignment of "float" *)
alignof_double = 2; (* Alignment of "double" *)
alignof_longdouble = 2; (* Alignment of "long double" *)
alignof_str = 1; (* Alignment of strings *)
alignof_fun = 1; (* Alignment of function *)
alignof_aligned = 16; (* Alignment of a type with aligned attribute *)
char_is_unsigned = false; (* Whether "char" is unsigned *)
const_string_literals = true; (* Whether string literals have const chars *)
little_endian = true; (* whether the machine is little endian *)
underscore_name = true; (* If assembly names have leading underscore *)
has__builtin_va_list = false; (* Whether [__builtin_va_list] is a known type *)
__thread_is_keyword = false; (* Whether [__thread] is a keyword *)
}
let mach2 = { xc16 with compiler = "baz" }
let () =
let ran = ref false in
Cmdline.run_after_loading_stage
(fun () ->
Kernel.result "Registering machdep 'xc16' as 'XC16'";
File.new_machdep "XC16" xc16;
if !ran then begin
Kernel.result "Trying to register machdep 'mach2' as 'XC16'";
File.new_machdep "XC16" mach2
end
else ran := true
)
我在行#34之前的文件__fc_machdep.h中插入了以下行; #error必须定义..."
#ifdef __FC_MACHDEP_XC16
#define __FC_BYTE_ORDER __LITTLE_ENDIAN
/* min and max values as specified in limits.h */
#define __FC_SCHAR_MAX 0x7f
#define __FC_SCHAR_MIN (-__FC_SCHAR_MAX -1)
#define __FC_UCHAR_MAX 0xff
#define __FC_CHAR_MIN __FC_SCHAR_MIN
#define __FC_CHAR_MAX __FC_SCHAR_MAX
#define __FC_SHRT_MAX 0x7fff
#define __FC_SHRT_MIN (-__FC_SHRT_MAX -1)
#define __FC_USHRT_MAX 0xffff
#define __FC_INT_MAX __FC_SHRT_MAX
#define __FC_INT_MIN __FC_SHRT_MIN
#define __FC_UINT_MAX __FC_USHRT_MAX
#define __FC_LONG_MAX 0x7fffffff
#define __FC_LONG_MIN (-__FC_LONG_MAX -1)
#define __FC_ULONG_MAX 0xffffffffU
#define __FC_LLONG_MAX 0x7fffffffffffffffLL
#define __FC_LLONG_MIN (-__FC_LLONG_MAX -1)
#define __FC_ULLONG_MAX 0xffffffffffffffffUL
/* Required */
#undef __CHAR_UNSIGNED__
#define __WORDSIZE 16
#define __SIZEOF_SHORT 2
#define __SIZEOF_INT 2
#define __SIZEOF_LONG 4
#define __SIZEOF_LONGLONG 8
#define __CHAR_BIT 8
#define __PTRDIFF_T int
#define __SIZE_T unsigned int
#define __FC_SIZE_MAX __FC_INT_MAX
/* stdio.h */
#define __FC_EOF (-1)
#define __FC_FOPEN_MAX 8
#define __FC_RAND_MAX 32767
#define __FC_PATH_MAX 260
#define __WCHAR_T unsigned short
/* Optional */
#define __INT8_T signed char
#define __UINT8_T unsigned char
#define __INT16_T signed int
#define __UINT16_T unsigned int
#define __INTPTR_T signed int
#define __UINTPTR_T unsigned int
#define __INT32_T signed long
#define __UINT32_T unsigned long
#define __INT64_T signed long long
#define __UINT64_T unsigned long long
/* Required */
#define __INT_LEAST8_T signed char
#define __UINT_LEAST8_T unsigned char
#define __INT_LEAST16_T signed int
#define __UINT_LEAST16_T unsigned int
#define __INT_LEAST32_T signed long
#define __UINT_LEAST32_T unsigned long
#define __INT_LEAST64_T signed long long
#define __UINT_LEAST64_T unsigned long long
#define __INT_FAST8_T signed char
#define __UINT_FAST8_T unsigned char
#define __INT_FAST16_T signed int
#define __UINT_FAST16_T unsigned int
#define __INT_FAST32_T signed long
#define __UINT_FAST32_T unsigned long
#define __INT_FAST64_T signed long long
#define __UINT_FAST64_T unsigned long long
/* POSIX */
#define __SSIZE_T signed long
#define __FC_PTRDIFF_MIN __FC_INT_MIN
#define __FC_PTRDIFF_MAX __FC_INT_MAX
#define __FC_VA_LIST_T char*
/* Required */
#define __INT_MAX_T signed long long
#define __UINT_MAX_T unsigned long long
#else
现在,如果我以这种方式启动Frama-C:
$ frama-c-gui -load-script machdep_xc16 -machdep XC16 -cpp-command 'C:\\"Program Files (x86)"\\Microchip\\xc16\\v1.26\\bin\\xc16-gcc.exe -E' -no-cpp-gnu-like D:\\project\\*.c
我得到这样的输出:
[kernel] Registering machdep 'xc16' as 'XC16'
[kernel] Parsing .opam/4.02.3+mingw64c/share/frama-c/libc/__fc_builtin_for_normalization.i (no preprocessing)
[kernel] warning: machdep XC16 has no registered macro. Using __FC_MACHDEP_XC16 for pre-processing
[kernel] Parsing D:/project/main.c (with preprocessing)
. . .
[kernel] Parsing D:/project/get_data.c (with preprocessing)
[kernel] syntax error at .opam/4.02.3+mingw64c/share/frama-c/libc/__fc_define_wchar_t.h:28:
26 #if !defined(__cplusplus)
27 /* wchar_t is a keyword in C++ and shall not be a typedef. */
28 typedef __WCHAR_T wchar_t;
^^^^^^^^^^^^^^^^^^^^^^^^^^
29 #else
30 typedef __WCHAR_T fc_wchar_t;
处理包含#include <stdio.h>
的文件时发生语法错误
我做错了什么?
答案 0 :(得分:4)
有关如何添加新machdep的说明已在手册中进行了修订,并将在下一个Frama-C版本(Phosporus)上提供。
新machdep的主要问题是machdep有两个(看似多余的)部分:Frama-C使用的OCaml级定义,以及C预处理器在解析时使用的C级定义Frama-C标准库。认识到两者都是必需的和互补的,有助于理解为什么整个过程很麻烦(尽管将来会简化)。
以下是即将发布的说明摘录:
自定义机器描述可以如下实现:
let my_machine = {
version = "generic C compiler for my machine";
compiler = "generic"; (* may also be "gcc" or "msvc" *)
cpp_arch_flags = ["-m64"];
sizeof_short = 2;
sizeof_int = 4;
sizeof_long = 8;
(* ... *)
}
let () = File.new_machdep "my_machine" my_machine
请注意,您的machdep_xc16.ml
可以简化:您使用的代码是尝试注册两次相同machdep的测试的一部分,只是为了确保它失败。但实际上,当你使用-load-script
时,你可以像上面一样直接创建machdep,直接调用File.new_machdep
。
加载此代码后,可以指示Frama-C使用新机器 使用
-machdep
命令行选项的模型。如果您打算使用Frama-C的标准库标题,您还必须执行以下操作:
- 完成
定义常量
__FC_MACHDEP_<CUSTOM>
,替换<CUSTOM>
使用您创建的machdep的名称(大写字母); 这可以通过-cpp-extra-args="-D__FC_MACHDEP_<CUSTOM>"
;提供一个头文件,其中包含与您的caml对应的宏定义 定义。在大多数情况下,这些是以
__FC_
为前缀的宏, 对应于标准C宏定义,例如,__FC_UCHAR_MAX
。 Frama-C使用这些定义<limits.h>
和其他标头提供标准C定义。 测试文件tests/misc/custom_machdep/__fc_machdep_custom.h
包含所需定义的完整示例。其他例子可以 可以在share/libc/__fc_machdep.h
找到。确保您的自定义标头定义
__FC_MACHDEP
包括警卫,并且您正在分析的程序包括此标题 在所有其他标题之前。确保这一点的一种方法,无需修改任何 源文件是在GCC中使用-include
等选项。完整命令行的示例如下所示,用于自定义 machdep名为
myarch
,在文件my_machdep.ml
中定义 使用machdep_myarch.h
中定义的stdlib常量:
frama-c -load-script my_machdep.ml -machdep myarch \
-cpp-extra-args="-D__FC_MACHDEP_MYARCH -include machdep_myarch.h"
请注意,Silicon中的__fc_machdep_custom.h
不完整,但您发布的版本似乎已完成,因此请使用它:将其放在一个名为eg的文件中。 machdep_xc16.h
,向其添加#define __FC_MACHDEP
,并将其包含在其他文件之前,例如使用-include machdep_xc16.h
作为预处理程序标志。这将确保使用您的machdep版本而不是Frama-C,这将允许您使用Frama-C的标准库以及根据您的体系结构定义的常量。
此外,由于您的命令行包含-cpp-command
和-no-cpp-gnu-like
,因此您必须调整上面的-cpp-extra-args
,直接将-D__FC_MACHDEP_MYARCH
和-include machdep_myarch.h
放入你的-cpp-command
。