Complexity checking of ARM programs, by deduction∗ Mário Pereira
Simão Melo de Sousa
LIACC & DCC-FC - University of Porto Rua do Campo Alegre 1021, 4169-007, Porto, Portugal
LIACC & LISP & Release & DI - University of Beira Interior Rua Marquês d’Ávila e Bolama, 6201-001, Covilhã, Portugal
[email protected]
ABSTRACT In this paper we address two main questions: how to reason about the correctness of unstructured programs (particularly programs written in ARM Assembly) and how to use a proof-based system to check computational complexity of such programs. We approach the correctness issue by applying a flow sequentialization methodology and a formalized semantics of ARM instructions. An annotated ARM program is turned into a set of purely sequential programs, then each instruction is mapped into the corresponding formalized opcodes and finally Why3’s VCGen is employed to generate proper Verification Conditions. Regarding complexity checking, we propose a methodology, based on the sequentialization process, by encoding instructions CPU-cost into their semantics and checking the program’s calculated cost against user-supplied cost information (cost properties will be treated as normal functional annotations). Along with the formalization of correctness and complexity reasoning techniques, a prototype tool has been implemented and used to verify both the correctness and complexity of some practical examples.
Keywords Deductive software verification, Hoare logic, Why3, unstructured control flow graph, ARM, complexity checking.
1.
INTRODUCTION
The task of deductive program verification [7] can be summarized as the task of turning the correctness of programs into a set of logical formulas which, if proven correct, imply the correctness of the program. Hoare Logic and the ∗This work is funded by ERDF - European Regional Development Fund through the COMPETE Programme (operational programme for competitiveness) and by National Funds through the FCT - Funda¸ca ˜o para a Ciˆencia e a Tecnologia (Portuguese Foundation for Science and Technology) within project AVIACC: FCOMP-01-0124-FEDER-020486
Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. SAC’14 March 24-28, 2014, Gyeongju, Korea. Copyright 2014 ACM 978-1-4503-2469-4/14/03 ...$15.00.
[email protected] Weakest Pre-condition Calculus provide formal mechanisms to annotate programs and correctly produce the mentioned formulas, the so-called Verification Conditions (VCs). Traditional deductive techniques are, however, restricted to the verification of programs with “well-behaved” flow structure, those which produce structured control flow graphs. The case of programs with unstructured nature is rather different: the unstructured control flow graph produced by this kind of programs does not present any point suitable for inserting annotations (any point in the program can be a loop entry point). This paper presents our work regarding the proof of unstructured programs. We apply a technique for pre-processing the structure of these programs so traditional deductive methods and tools can be applied. In particular we focus on programs written in ARM Assembly language (more specifically on the ARM7TDMI instruction-set) and employ the Why3 platform [4, 8] as a VCGen backend. Using the mentioned pre-processing technique and the Why3’s logic we propose a methodology for checking the complexity of ARM programs against an overall expected cost. The cost of a program is calculated based on the amount and kind of CPU cycles each instruction spends on its execution. This presents two major advantages: using CPU cycles gives us a fine-grained measure for the cost of each program; second, since the cost for each ARM instruction is well-established, we can deterministically calculate the cost of a sequence of instructions, finally leading to the overall cost of the program. The paper is organized as follows. Section 2 explains in more detail the problems associated with the proof of unstructured programs and introduces the methodology used to overcome such issues. Section 3 describes the work on the encoding of the ARM Assembly’s semantics into the Why3’s logic. We propose a methodology for complexity checking in section 4 and explain how the instructions’ basic semantics should be refined so we can reason about programs’ complexity. Section 5 illustrates the use of the conceived platform with some practical examples. Finally, we conclude with some related work and yield final remarks along with possible future work (section 6 and section 7, respectively).
2. 2.1
PROVING UNSTRUCTURED PROGRAMS Unstructured Control Flow Graphs
The use of common jumping instructions (such as Assembly’s branching instructions or goto from C) may lead to programs represented by unstructured control flow graphs
Figure 1: Example of unstructured control flow graph.
seq1 , assume P re sub r0 , r0 , #1 sub r0 , r0 , #1 assert I1
seq2 , assume I1 cmp r0 , #0 assume cmp > 0 sub r0 , r0 , #1 sub r0 , r0 , #2 assert I1
seq3 , assume I1 cmp r0 , #0 assume cmp 0 sub r0 , r0 , #2 assert I1
seq5 , assume I2 cmp r0 , #0 assume cmp