REALISTIC CORRECT SYSTEMS IMPLEMENTATION
The present article and the forthcoming second part on Trusted Compiler Implementation address correct construction and functioning of large computer based systems. In view of so many annoying and dangerous system misbehaviors we ask: Can informaticians righteously be accounted for incorrectness of...
Збережено в:
| Дата: | 2015 |
|---|---|
| Автор: | |
| Формат: | Стаття |
| Мова: | English |
| Опубліковано: |
PROBLEMS IN PROGRAMMING
2015
|
| Теми: | |
| Онлайн доступ: | https://pp.isofts.kiev.ua/index.php/ojs1/article/view/3 |
| Теги: |
Додати тег
Немає тегів, Будьте першим, хто поставить тег для цього запису!
|
| Назва журналу: | Problems in programming |
| Завантажити файл: | |
Репозитарії
Problems in programming| id |
pp_isofts_kiev_ua-article-3 |
|---|---|
| record_format |
ojs |
| resource_txt_mv |
ppisoftskievua/6e/5edaaab261b0b7d0c5f046b8f5a8ee6e.pdf |
| spelling |
pp_isofts_kiev_ua-article-32018-09-26T13:18:29Z REALISTIC CORRECT SYSTEMS IMPLEMENTATION Goerigk, W. The present article and the forthcoming second part on Trusted Compiler Implementation address correct construction and functioning of large computer based systems. In view of so many annoying and dangerous system misbehaviors we ask: Can informaticians righteously be accounted for incorrectness of systems, will they be able to justify systems to work correctly as intended? We understand the word justification in the sense: design of computer based systems, formulation of mathematical models of information flows, and construction of controlling software are to be such that the expected system effects, the absence of internal failures, and the robustness towards misuses and malicious external attacks are foreseeable as logical consequences of the models. PROBLEMS IN PROGRAMMING ПРОБЛЕМЫ ПРОГРАММИРОВАНИЯ ПРОБЛЕМИ ПРОГРАМУВАННЯ 2015-06-12 Article Article application/pdf https://pp.isofts.kiev.ua/index.php/ojs1/article/view/3 PROBLEMS IN PROGRAMMING; No 1 (2003) ПРОБЛЕМЫ ПРОГРАММИРОВАНИЯ; No 1 (2003) ПРОБЛЕМИ ПРОГРАМУВАННЯ; No 1 (2003) 1727-4907 en https://pp.isofts.kiev.ua/index.php/ojs1/article/view/3/5 Copyright (c) 2015 ПРОБЛЕМИ ПРОГРАМУВАННЯ |
| institution |
Problems in programming |
| baseUrl_str |
https://pp.isofts.kiev.ua/index.php/ojs1/oai |
| datestamp_date |
2018-09-26T13:18:29Z |
| collection |
OJS |
| language |
English |
| topic |
|
| spellingShingle |
Goerigk, W. REALISTIC CORRECT SYSTEMS IMPLEMENTATION |
| topic_facet |
|
| format |
Article |
| author |
Goerigk, W. |
| author_facet |
Goerigk, W. |
| author_sort |
Goerigk, W. |
| title |
REALISTIC CORRECT SYSTEMS IMPLEMENTATION |
| title_short |
REALISTIC CORRECT SYSTEMS IMPLEMENTATION |
| title_full |
REALISTIC CORRECT SYSTEMS IMPLEMENTATION |
| title_fullStr |
REALISTIC CORRECT SYSTEMS IMPLEMENTATION |
| title_full_unstemmed |
REALISTIC CORRECT SYSTEMS IMPLEMENTATION |
| title_sort |
realistic correct systems implementation |
| description |
The present article and the forthcoming second part on Trusted Compiler Implementation address correct construction and functioning of large computer based systems. In view of so many annoying and dangerous system misbehaviors we ask: Can informaticians righteously be accounted for incorrectness of systems, will they be able to justify systems to work correctly as intended? We understand the word justification in the sense: design of computer based systems, formulation of mathematical models of information flows, and construction of controlling software are to be such that the expected system effects, the absence of internal failures, and the robustness towards misuses and malicious external attacks are foreseeable as logical consequences of the models. |
| publisher |
PROBLEMS IN PROGRAMMING |
| publishDate |
2015 |
| url |
https://pp.isofts.kiev.ua/index.php/ojs1/article/view/3 |
| work_keys_str_mv |
AT goerigkw realisticcorrectsystemsimplementation |
| first_indexed |
2025-07-17T10:05:23Z |
| last_indexed |
2025-07-17T10:05:23Z |
| _version_ |
1850413091109470208 |
| fulltext |
Теоретические и методологические основы программирования
© Wolfgang Goerigk, Hans Langmaack, 2003
ISSN 1727-4907. Проблемы программирования. 2003. № 1 3
UDC 681.3.51
Wolfgang Goerigk, Hans Langmaack
REALISTIC CORRECT SYSTEMS IMPLEMENTATION
The present article and the forthcoming second part on Trusted Compiler Implementa-
tion address correct construction and functioning of large computer based systems. In view
of so many annoying and dangerous system misbehaviors we ask: Can informaticians
righteously be accounted for incorrectness of systems, will they be able to justify systems
to work correctly as intended? We understand the word justification in the sense: design
of computer based systems, formulation of mathematical models of information flows, and
construction of controlling software are to be such that the expected system effects, the
absence of internal failures, and the robustness towards misuses and malicious external at-
tacks are foreseeable as logical consequences of the models.
Since more than 40 years, theoretical informatics, software engineering and compiler
construction have made important contributions to correct specification and also to correct
high-level implementation of compilers. But the third step, translation - bootstrapping - of
high level compiler programs to host machine code by existing host compilers, is as impor-
tant. So far there are no realistic recipes to close this correctness gap, although it is known
for some years that trust in executable code can dangerously be compromised by Trojan
Horses in compiler executables, even if they pass strongest tests.
In the present first article we will give a comprehensive motivation and develop
a mathematical theory in order to conscientiously prove the correctness of an initial fully
trusted compiler executable. The task will be modularized in three steps. The third step of
machine level compiler implementation verification is the topic of the forthcoming second
part on Trusted Compiler Implementation. It closes the implementation gap, not only for
compilers but also for correct software-based systems in general. Thus, the two articles to-
gether give a rather confident answer to the question raised in the title.
1. Introduction
Users of computer based systems
are often heavily annoyed by errors, fail-
ures and system crashes. In our every day
experience using programs we observe
them to fail, for instance due to lack of
memory, programming errors, compiler
bugs, or misuses of optimizing compilers
under wrong assumptions. Although very
annoying, we all live with software errors,
but we still hope that application pro-
grammers, compiler constructors, operat-
ing system designers and hardware engi-
neers have at least been sensible enough
to detect and to signal any such error.
Undetected errors might have harmful
consequences, in particular if they are
intentional, perhaps due to viruses or
Trojan Horses.
Often the user is accountable, us-
ing systems outside their specified do-
mains without even reading manuals or
documentation. However, a large number
of system misbehaviors is still due to the
system constructors themselves, to pro-
fessionals, computer scientists, informati-
cians. It is obvious that they should take
responsibility as any professional has to.
But software constructors and their com-
panies hardly ever give guarantees for
their products. And they are not even en-
forced to because customers purchase
software products in full awareness of de-
fects. Nevertheless, informatics scientists
and producers of computer based systems
are responsible and not allowed to per-
manently neglect the problem of system
misbehaviors in practice.
1.1. Motivation and Outline. Our
article addresses correct construction and
functioning of large computer based sys-
tems. In view of so many annoying and
dangerous system misbehaviors we ask
(and positively answer) the question: Can
informaticians be righteously accounted for
system weaknesses, will they be able to
justify systems to work correctly as in-
tended, to be dependable, reliable, robust?
Since hardware turns out to be
quite reliable, the question comes down
to software, i.e. to abstract and mathe-
matically treatable components of sys-
tems. The rigid nature of matter educates
hardware technologists to be extremely
sensitive towards hardware failures; they
Теоретические и методологические основы программирования
4
are felt as sensations. So system faults are
mostly and increasingly caused by soft-
ware. This observation is crucial and
matches the clear delimitation of respon-
sibilities between hardware and system
software engineering. Software engineers
are permitted to assume hardware to work
correctly, and to exploit this assumption
for equally sensitive, rigorous low level
implementation verification of software.
Once software engineers and application
programmers can count on (trust in) the
correctness of their low level machine
implementations and integrated systems,
an equal status of sensitivity also for
software faults becomes justifiable.
That is to say, at the low end, sys-
tem software engineering meets hardware
engineering, and at the upper end, com-
piler constructors and system software
engineers meet application programmers
and software engineers. They want to ex-
press their software in problem-oriented
languages and rely on machine inde-
pendent semantics. Compiler constructors
cannot be made responsible for applica-
tion program faults. Actually, a compiler
has to be constructed without any knowl-
edge about the intended meaning of ap-
plication programs. The contract has to
be with respect to program semantics. As
a return, the application programmer ex-
pects correctly implemented machine ex-
ecutables. But both, application and sys-
tem programmers have to be aware of
what kinds of implementation correct-
nesses make sense and can realistically
be guaranteed. We will reflect realistic
requirements and introduce the notion of
relative correctness and its preservation
and variants in view of data and program
representation and of errors which can be
accepted or others which have to be
avoided.
Although an area of research and
development since 40 years, realistic lan-
guage implementation, a central topic in
system software engineering, is still a se-
vere gap in trustworthiness. Practical
compiler construction proceeds in three
steps: (1) Specification of a compiling re-
lation from source language to target
machine code, (2) implementation of the
compiling relation as a compiler program
in an appropriate high level system pro-
gramming language, and (3) boot-
strapping the compiler, i.e. translation of
the compiler source program into host
machine code using an existing host
compiler. Theoretical informatics, soft-
ware engineering and compiler construc-
tion have importantly contributed to-
wards correctness of the first two steps.
1.1.1. Trusted Compiler Imple-
mentation. But how to verify the third,
the low level step? So far there are no
realistic recipes to close this gap, al-
though it is known for many years (at
least since Ken Thompson's Turing
Award lecture in 1984) that trust in ex-
ecutable code can dangerously be com-
promised by Trojan Horses in compiler
executables, even if they pass strongest
tests. Our article will show how to close
this low level gap. The Deutsche For-
schungsgemeinschaft (DFG) research
group Verifix has developed the method
of rigorous syntactic a-posteriori code in-
spection in order to remove every source
of crucial faults in initial compilers for
appropriate high level system program-
ming languages. The method employs
multi-pass translation with tightly
neighboring intermediate languages and
a diagonal bootstrapping technique
which effectively is based on the above
mentioned correctness assumptions and
deliberations. A-posteriori result checking
is applicable for the construction of veri-
fied compiler generators as well, and it is
crucial to the development of strategies
to substitute existing system software by
proved correct modifications.
There is a current trend for system
software to be required open source,
enabling source code scrutiny for operat-
ing system components, networking soft-
ware and also for compilers and other
tools and utilities. This will definitely un-
veal a lot of bugs and even malicious
code like Trojan Horses or so-called
easter eggs. However, we want to stress,
that the open source idea crucially de-
pends on trusted compilation. Source
level scrutiny does not sufficiently guar-
antee trustworthiness of executable soft-
Теоретические и методологические основы программирования
5
ware [Thompson84, Goerigk99b, Goe-
rigk00a, Goerigk00b]. There are sophisti-
cated and intelligent techniques to com-
pletely hide Trojan Horses in binary
compiler executables, which are not part
of the alleged source code, but might
cause unexpected, arbitrary, even catas-
trophic effects if target programs are
eventually executed. No source code
scrutiny, no source level verification, no
compiler validation, virtually no test, not
even the strong compiler bootstrap test
does help. Note that in this situation it is
also very unlikely that any of the known
security techniques will help, because not
even the application programmer can
give a guarantee that her/his delivered
application has not been compromised by
auxiliary software utilities or compilers
used during software construction.
Industrial software production for
realistic safety and security critical appli-
cations enforces immense checking ef-
forts. The amount of work is apparently
unmanageable, and consequently, it is
left undone. That is to say: On the one
hand, we observe dangerous omissions in
industrial practice. On the other hand, we
realize how enormous the problems are.
Thus, informatics science, in particular
viewed at as an engineering science, has
to attack them as problems of basic re-
search – supported by research funding
institutions like Deutsche Forschungsge-
meinschaft (DFG) or German Federal
Board of Safety and Security in Informa-
tion Technology (Bundesamt für Sicher-
heit in der Informationstechnik, BSI), in-
stitutions which we find in all states with
high science and technology standards.
We are not allowed to leave industry
people alone with their responsibility for
necessary efforts which are seemingly
unsurmountable at present. It is neces-
sary to clearly identify the problems and
to work towards methods for their rigor-
ous solution which work out in practice.
Mathematics as the classical structure
science helps. Again and again, mathe-
maticians invent ways of gaining and
communicating insights, which are rigor-
ous and convincing even though or
maybe even because they are not com-
pletely formal. We shall see that in the
central area of correct compiler construc-
tion and implementation our techniques
of insight can cope with realistic software
tasks, and of course then can serve as a
model outside the area of compilers. Ac-
tually, it is the too often neglected low
level implementation verification of so-
called initial compilers which involves a
certain amount of manual checking and
proving [Goerigk/Langmaack01b]. For
principle reasons we cannot leave all
checking work to programmed computers
if we do not want to run into circuli
vitiosi. Trust in any executed program
would furtheron dangerously and hope-
lessly depend on auxiliary software of
uncertain pedigree [HSE01].
We do not want to blame or con-
demn anybody personally. The problem is
enormous, very awkward, and in certain
central areas it seems nearly unreasonable
to ask for problem solutions in depth.
However, because of potential disastrous
consequences, informaticians must attack
the problem and seek for solutions to
give rigorous guarantees. And we shall
see that in the crucial area of correct
compiler construction, informatics sci-
ence can achieve quite a lot. There is a
remarkable interplay of informatics as a
foundational structure science and as an
engineering science.
The realistic recipe of bootstrap-
ping and syntactical a-posteriori code in-
spection, which Verifix has developed in
order to close the low level implementa-
tion gap rigorously, and which has been
applied to a realistic compiler executable
for a useful systems programming lan-
guage, is the topic of the second article
on Trusted Compiler Implementation [Go-
erigk/Langmaack01b].
1.2. Notions Mentioned in the
Title. Let us briefly explain the notions
which we mentioned in the title of this
essay: Informatics (Computer Science in
the Anglo-American literature) is the sci-
entific discipline of design, construction
and networking and of application and
programming of computers (often called
processors). Although not the most mod-
ern one, this definition is well stressing
Теоретические и методологические основы программирования
6
the two important areas of work: hard-
ware and software. Computer based sys-
tems (CBS) are engineering systems with
embedded computers, programs, sensors,
actuators, clocks and connecting chan-
nels in a physical environment [Schwei-
zer/Voss96]. Realistic computer based
systems use to be large, complex, and
safety and/or security critical [Laprie94].
The latter means that systems may cause
heavy damages to health and economy
by unintended (internal) failures and by
intended (external) attacks.
As a matter of fact, the bare exis-
tence of large computer based systems is
justified. We need them. But what about
correct construction and functioning of
such systems? Can informaticians be
made responsible, be accounted for, will
they be able to justify systems to work
correctly as intended? We use the term
justification in this sense, i.e. for the de-
sign of computer based systems, the for-
mulation of mathematical models of in-
formation flows in systems and the con-
struction of software to be such that the
expected system effects and the absence
of failures and violations are foreseeable
as logical consequences of the models
alone. Not every system has such sub-
stantial delineable area which can be jus-
tified in this rigorous sense. In our opin-
ion, however, if such a rigorous treatment
is possible, it should be required for high
safety and security standards. If we can
logically foresee (infer) every desired
property, especially safety and security
properties, then we say that the computer
based system has been (mathematically)
proved correct, has been verified. We use
the word verification in this sense,
whereas validation means finding by ex-
periments that a system fulfills our in-
tents. Validation is not our main topic in
this essay.
1.3. Consistent Checkability of
Software Production Processes. Large
computer based systems are essentially
controlled by embedded processors and
their software. General experience shows
that the hardware processors actually
work by far more reliably than software
does and, hence, the weaknesses of com-
puter based systems are in most cases
due to software problems. Every software
production (implementation) process to-
day still has two major gaps in trustwor-
thiness of consistent checkability, namely
the transitions from
1. software design to high level
source code (high level software engi-
neering) and
2. from high level code to inte-
grated executable binary machine code
(realistic compilation).
Both gaps are under investigation
in research and development since more
than 30 years, but nevertheless even real-
istic compilation is still a severe gap in
trustworthiness [BSI96]. Strictly speaking,
realistic compilers are not correct and no
compiler has yet sufficiently been veri-
fied. So the question arises whether in-
formatics and in particular theoretical
computer science, programming language
theory, compiler construction and soft-
ware engineering do not have any useful
results to help in this situation. They
have. And the insights are deep and also
practical. But we have to admit that the
results are often depending on too many
complicated assumptions which the prac-
tical user has to check for in realistic
situations. And unfortunately, in practice
this so far requires many properly edu-
cated engineers and a lot of mathemati-
cal and logical skill.
If we seriously look at informatics
also as an engineering science, we ought
to demonstrate solutions and to show that
the necessary checking can be done in a
thorough and convincing way. In particu-
lar, in this essay we will demonstrate a
strategic solution to close the second
gap, that of correct realistic compilation,
which in turn is necessary for a convinc-
ing high level software engineering.
1.4. DFG-Research Project Verifix-
Correct Compilers. Correct realistic
compilation is the major goal of the
German joint project Verifix on Correct
Compilers of the universities of Karlsruhe
(G. Goos, W. Zimmermann), Kiel (W.
Goerigk, H. Langmaack) and Ulm (A.
Dold, F.W. von Henke). Verifix is a DFG-
funded research group since 1996. The
goal is to develop repeatable engineering
Теоретические и методологические основы программирования
7
repeatable engineering methods for con-
structing correct compilers and compiler
generators
• for realistic, industrially applica-
ble imperative and object-oriented source
programming languages and
• real world target and host proc-
essors
• which, by help of mechanical
proof support (e.g. by PVS [Owre+92] or
ACL2 [Kaufmann/Moore94]) and by ex-
ploiting the idea of a-posteriori result
checking are rigorously verified as execu-
table host machine programs and
• which nevertheless generate ef-
ficient code that compares to unverified
compilers.
• Verifix uses practically and in-
dustrially approved compiler construction
methods
• and the proof methodology sup-
plements compiler construction, not vice
versa.
Compiler construction is crucial to
the construction of (large) computer
based systems, and correct realistic com-
pilers are necessary for a convincing con-
struction process of correctly working
systems. Systems consist of hardware and
controlling software, and software splits
in system and application software. Com-
piler programs are system software, and
even compilers like any other piece of
systems or applications are executable by
compiling into binary processor code.
There is no doubt that it is reasonable to
require compiling to be correct.
Fig 1. The central role of correct compilers
Sometimes we use the termini fully
correct or fully verified if we want to em-
phasize that not only a mathematically
specified compiling relation CSL
TL between
source language SL and target language
TL is proved correct, but that also an ex-
ecutable compiler version implementing
this relation and implemented in binary
HML-machine code of a real world host
processor HM is proved correct without
depending on any auxiliary unchecked
tool execution. Note that the term fully
correct makes sense for arbitrary software
as well, which is mathematically specified
on the one hand, and implemented on a
machine on the other.
We will make a difference between
the terms proved correct and provably
correct. We use provably correct in order
to indicate that we are interested to de-
velop methods which generate proof
documents, often aided by computers.
These documents can rigorously be
checked to be proofs1. If the documents
are checked, for instance for a concrete
compiler, we use the term proved correct.
Of course, we have to admit that check-
ing might bear errors. So proved does not
claim absolute truth. But it claims a rig-
orous attempt to gain mathematical cer-
tainty, which is much more than many
other research areas can achieve.
It is not true, that investigation
into correct realistic compilation does not
pay off just because software design and
high level software engineering probably
show up many more faults than compila-
tion. Unless we close the lower level gap
with mathematical certainty, a major goal
of Verifix, potential incorrect compilation
will always critically disturb the recogni-
tion of certainties resp. uncertainties in
high level software engineering. Correct
realistic compilation establishes a trust-
worthy execution basis for further soft-
ware development.
Informatics is well responsible for
compilers with their program semantics
and machines. Full verification of com-
pilers is manageable and feasible. Com-
pared to programming language theory
and compiler construction practice, no
other discipline of practical computer
science is so well equipped with theory.
Investigations in Verifix have brought up
ideas and methods to incrementally re-
place compilers and to replace or encap-
1 by more or less skilled informaticians. The
required skill varies. Not every checking work
requires trained mathematicians or logicians.
Теоретические и методологические основы программирования
8
sulate system software components by
fully verified software.
1.5. Levels of Trustworthiness and
Quality. The lower level gap due to real-
istic compilation has been made public
by governmental boards like the German
BSI, but also in other countries. In 1989,
BSI published IT-safety and security lev-
els (of trustworthiness or IT-quality)
[ZSI89]. In Germany, there are eight lev-
els from Q0 (unsufficiently checked) up
to Q7 (formally verified, proofs and im-
plementation are performed by officially
admitted tools).
However, an "officially admitted"
tool (like a compiler or theorem prover)
is not necessarily fully verified. So for in-
stance a compiler just needs to pass an
official validation test suite. It is well-
known, that such tests do not suffice nor
replace correctness proofs [Dijkstra76].
Official IT-certification prescriptions like
those published by BSI in 1989/90/94
[ZSI89, ZSI90, BSI94] require:
"The compilers employed must be offi-
cially validated and be admitted as
implementation tools for Q7-systems
by an official evaluation board."
The terminus validated reveals that
for tools like compilers the evaluation
boards at present can only validate for
instance by applying official test suites.
The boards do not see any other rigorous
checking or proof technique and hence
suspect that one is not allowed to trust in
the correctness of generated machine
code and hence of any compiler. Thus,
consequently BSI added the following
additional requirement:
“The transformations from source to
target code executed by a compiler
program on a host machine must be a-
posteriori checkable (“nachvollzieh-
bar”, “inspectable”).”
For this reason certification au-
thorities still do not trust in any existing
realistic compiler. Instead, they often per-
form parallel semantical inspections of
both high level code and low level ma-
chine code [Pofahl95], i.e. they check a-
posteriori that the target code will work
as expected from the source code.
Such a code-inspection is a rigor-
ous a-posteriori checking of the target
program πTL to perform as expected from
the source program πSL, where the target
program is the result of a successful
compilation of the (well-formed) source
program. The hope is that this is feasible
if the mapping CSL
TL (the specification of
the transformation) from source to target
programs is “inspectable”, and hence that
it is sufficient to check
(πSL, πTL) ∈ CSL
TL.
However, as long as CSL
TL is not
proved correct, the checking involves
semantical considerations.
Inspection resp. a-posteriori result
checking is an old idea [Blum+89]. And
we know the method from school
mathematics: since for instance integer
division is felt more error prone than
multiplication, we double-check the re-
sults of division by multiplication. We
also use to double-check the results of
linear equations solutions by simpler ma-
trix-vector-multiplication. By code inspec-
tion with respect to compilers we mean
the a-posteriori result checking of com-
piler generated code. Result checking is
often much easier than (a-posteriori) veri-
fication. Moreover, it is an interesting ob-
servation, that industrial software engi-
neers and certification boards trust the
technique of a-posteriori result checking.
Although there is a well-established and
reasonably developed program verifica-
tion theory, it is often not well-applicable
to large systems or even large amounts of
low level code. Therefore it is so interest-
ing to observe, both from a theoretical
and from a practical point of view, that
realistic scientifically founded fully veri-
fied compiler construction has to reach
back also to a-posteriori checking to a
small, but decisive extent.
We will see this later while proving
low level compiler implementation
correctness [Goerigk/Langmaack01b] and
hence full compiler correctness. Conse-
quently, since this is possible and feasi-
ble, already in 1989/90 one of the authors
proposed to introduce an even higher IT-
safety and security level of quality Q8
Теоретические и методологические основы программирования
9
(Production, proof and checking tools are
fully verified, not only at high level, but
also down to implementations in execu-
table binary machine code). Otherwise,
the low level gap of realistic compilation
will remain open forever.
2. Code Inspection in Compiler Con-
struction Processes
The Verifix-thesis is that after 40
years compiler construction and more
than 30 years software engineering it
should no longer be necessary to inspect
low level generated code, not even for
safety and security critical software. The
new higher quality level Q8 should be
introduced which is reaching beyond Q7.
It should be desirable and required for
industrial software construction, in par-
ticular for realistic compilers. We cannot
entirely avoid manual low level code in-
spection [Fagan86], however, it is only
necessary for initial compiler executables
which cannot be implemented on behalf
of a verified bootstrapping compiler ex-
ecutable. The requirement for low level
code inspection only make sense in this
respect. In principle, it should suffice to
perform this work exactly once. However,
realistic industrial correct compiler engi-
neering additionally needs repeatable
methods for constructing correct initial
compiler implementations from the
scratch whenever necessary.
The goal of correct realistic com-
piler construction in the view of Verifix is
that compiler executables on real world
host machines have to be provably cor-
rect, and if they are to be used for safety
and security critical software implementa-
tion, they have to be proved correct. That
means, that any executable binary ma-
chine program successfully generated
from a well-formed source program is
provably or proved correct with respect
to the source program semantics. Ma-
chine program correctness may only de-
pend on
• the correctness of source level
application programs with respect to their
specifications,
• hardware, i.e. target and host
processors to work correctly as described
in their instruction manuals,
• correct rigorous (mathematical,
logical) reasoning
Application programmers are re-
sponsible for the first assumption and
hardware designers for the second. Hence,
the compiler constructor only needs con-
sider the semantics of well-formed source
programs and processors and needs not
respect any further intention of system or
application programmers.
Since correctness of a compiler is
defined by correctness of ist resulting
target programs, we only depend on this
property which equally well can be estab-
lished by a-posteriori result checking. In
that case we sometimes use the term veri-
fying compiler. Suppose we have a given
unverified compiler τHL from SL to TL
written (or generated) in some high level
host programming language HL. Suppose
that τHL compiles via intermediate lan-
guages
SL = IL0, IL1, ..., ILm = TL, m ≥ 1,
by compiler passes
τ1
HL; τ2
HL; ...; τm
HL = τHL
which for a well-formed source program
πSL may successfully generate intermedi-
ate programs
πSL = πIL0, πIL1, ..., πILm = πTL.
For all passes τi
HL we assume that
we are able to write a-posteriori code in-
spection procedures γi
HL which we insert
into τHL:
τ1
HL; γ1
HL; τ2
HL; γ2
HL; ...; τm
HL; γm
HL = τ´HL.
Syntax and static semantics of τHL
has to make sure that the unverified
passes τi
HL are safely encapsulated such
that their semantics cannot interfere with
the inspection procedures nor with any
other passes. This method is obviously
relying on the existence of an initial cor-
rect and correctly implemented compiler
from HL to the compiler host machine
code, because it is by no means realistic
to assume HL to be a binary machine
language.
Теоретические и методологические основы программирования
10
In practice, there is no way around
an initial correct compiler executable on
some host machine. Moreover, HL should
at least be usable, if not comfortably us-
able, for systems programming and writ-
ing compilers.
Since programming languages,
their semantics, hardware processors and
their binary machine codes can accep-
tedly be modeled using mathematics,
correct compiler specification and im-
plementation are in principle mathemati-
cal tasks. Perhaps they are not that deep,
however, they require an exorbitant or-
ganization which is to be convincing and
without any logical gap.
Hardware engineering has, for
good money reasons, developed an error
handling culture by far better than soft-
ware engineering [Goerke96]. Hardware
errors are sensations, whereas software
errors are commonplace. Since hardware
errors cannot easily be repaired, they
bear the risk of high economic damage.
Thus, hardware engineers seek even for
small gaps where faults could creep in.
Seemingly, software errors can easily be
repaired. But often bug fixes make things
even worse, and also software errors bear
a high risk.
If we assume hardware correct,
then we can rely on hardware processors
programmed by correct and correctly im-
plemented software. However, if a proc-
essor is endowed with verified high level
programs, but additionally with some
non-verified compilers, then it generally
will not work failure-free for the time be-
ing. But the goal of fully reliable systems
software is not hopeless. We will come
back to this.
3. Related Work on Compiler Verification
Let us ask if literature does help in
order to prove the three compiler imple-
mentation steps correct. Actually, we find
intensive work on steps 1 and 2, although
often under unrealistic assumptions so
that the results have to be handled with
care. Step 3 has nearly totally been ne-
glected. If the phrase ``compiler verifica-
tion´´ is used, then most of the authors
mean step 1. There is virtually no work
on full compiler verification. Therefore,
the ProCoS project (1989—1995) has
made a clear distinction between compil-
ing verification (step 1) and compiler im-
plementation verification (steps 2 and 3).
Compiling verification is part of
theoretical informatics and program se-
mantics and work on it has been started
by J. McCarthy and J.A. Painter in 1967
[McCarthy/Painter67]. Proof styles are
operational [McCarthy/Painter67, Boer-
ger/Rosenzweig92, Boerger/Schulte98] or
denotational [Milne/Strachey76] depend-
ing on how source language semantics is
defined. If a source language has loops or
(function) procedures, then term rewriting
or copy rule semantics is employed
throughout [Langmaack73, Loeckx/Sie-
be87]. Other operational styles split in
natural [Nielson/Nielson92] or structural
[Plotkin81] operational or state-machine-
like [Gurevich91, Gurevich95]. Denota-
tional semantics has started with D. Scott's
work [Scott70, Scott/Strachey71], and
typical compiling correctness proofs can
be found in [Milne/Strachey76]. The au-
thors in [Hoare+93, Sampaio93, Mueller-
Olm96, Mueller-Olm/Wolf00] use an al-
gebraic denotational style for clearer
modular proofs, based on state transfor-
mations resp. predicate transformers.
Mechanical proofs are often based
on interpreter semantics, a further variant
of the operational style [Stoy77], and
sometimes include high level compiler
implementation verification (step 2) with
e.g. HL = Stanford-Pascal [Polak81] or
Boyer/Moore-Lisp [Moore88, Flatau92,
Moore96] or Standard-ML [Curzon93a,
Curzon94]. M. Broy [Broy92] uses the
Larch-prover [Garland/Guttag91]. One
should keep in mind, however, that the
running theorem prover implementations
are, strictly speaking, not completely
verified. Their correctnesses again de-
pend on existing correct initial host com-
pilers, which are not available up to now.
Recalling section 1, hackers might
have intruded Trojan Horses [Thomp-
son84, Goerigk99b] via unverified start
up compilers. Hence, we are left on hu-
man checkability of mechanical proof
protocols (a-posteriori-proof checking).
Теоретические и методологические основы программирования
11
High level compiler implementa-
tion verification (step 2) is a field within
software engineering. Correct implemen-
tation rules have been worked out in
many formal software engineering meth-
ods and projects like VDM [Jones90],
RAISE [George+92], CIP [Bauer78,
Partsch90], PROSPECTRA [Hoffmann/-
Krieg-Brueckner93], Z [Spivey92], B [Ab-
rial+91], and also the PVS-system
[Dold00].
Literature on low and machine
level compiler implementation verifica-
tion (step 3) is by far too sparse. There
are only demands by some researchers
like Ken Thompson [Thompson84], L.M.
Chirica and D.F. Martin [Chirica/Mar-
tin86] and J S. Moore [Moore88, Mo-
ore96], no convincing realistic methods.
Here is the most serious logical gap in
full compiler verification. Unfortunately,
a majority of software users and engi-
neers – as opposed to mathematicians
and hardware engineers – do not feel
logical gaps to be relevant unless they
have been confronted with a counter-
example. So we need
A. convincing realistic methods
for low level implementation verification
(step 3)
B. striking counter-examples (fail-
ures) in case only step 3 has been left out.
Let us first step into B and hence
go on with an initial discurs on the po-
tential risk of omitting the low level ma-
chine code verification step for compilers:
It is possible to construct a mali-
cious compiler executable which cor-
rectly compiles any but exactly two
source programs [Goerigk99b, Thomp-
son84]. One exception can be chosen ar-
bitrarily, and the compiler can be con-
structed to generate arbitrary, perhaps
catastrophic target code – for instance a
security relevant back door in the Unix
login procedure. The second exception is
the compiler's own source code. The ex-
ecutable will reproduce itself if applied to
this source code. If such a compiler gets
used by accident as the pre-initial auxil-
iary tool for compiler implementation,
without checking its result, it will pro-
duce an executable which still behaves
maliciously, generates incorrect code for
two programs, and one of them might
eventually cause a catastrophe. It is very
unlikely to find this program and thus
such a hidden Trojan Horse by classical
testing or compiler validation. Even
Wirth's bootstrap test is passed, because
the incorrect executable is constructed to
reproduce itself in that case, and of
course arbitrarily often, no matter if the
compiler has been verified on source
level or not.
Additional low-level implementa-
tion verification guarantees correctness
and the absence of such malicious behav-
ior. The initial compiler executable then
provides a trusted execution basis neces-
sary in particular also for achieving secu-
rity. This is the topic of the companion
paper [Goerigk/Langmaack01b].
4. Towards Trusted Realistic Compilation
Experience in realistic compiler
construction shows that in order to con-
struct correct compilers we are allowed to
restrict ourselves to sequential imperative
programming languages. For compilation
we need no process programming nor any
reactive or real-time behavior; compilers
are sequential (and transformational) and
we only depend on the correctness of
their resulting target programs. This in-
sight crucially facilitates the foundational
investigation in full compiler correctness
proofs including the essential (and so far
missing) implementation correctness
proofs for executable compiler host ma-
chine code. Implementations of realistic
compilers are constructed
• in sequential, mostly in impera-
tive languages,
• even if concurrent process or
real-time languages are to be compiled.
Consequently, we will study cor-
rect realistic compilation for sequential
imperative programming languages, and
in particular we restrict ourselves to
transformational programs (cf. Section 5),
because we are mainly interested in the
input/output relations defined by pro-
gram semantics. We need full compiler
correctness proofs only
Теоретические и методологические основы программирования
12
• for one initial compiler per
processor family with identified target
and host machine language TML = HML
• and for one sufficiently high-
level source language SL which allows for
formulating compilers and system pro-
grams.
All further compilers, e.g. optimiz-
ing compilers or those for more expres-
sive system programming languages SL1,
compiler generators, any further systems
software like provers, proof assistants and
proof checkers need no further correct
implementation steps below SL or SL1. In
particular, no further machine code in-
spection is necessary, and executable bi-
nary versions of these programs can be
generated purely mechanically following
N. Wirth [Wirth77]. The resulting code is
proved to be correct due to a bootstrap-
ping theorem [Goerigk/Langmaack01b],
also found in [Langmaack97a, Goe-
rigk99a, Goerigk/Langmaack01, Goerigk-
/Langmaack01a]. As a conclusion we
want to stress, that the second software
production process gap (cf. [Goerigk/-
Langmaack01b]) can be closed if the
Verifix-recipes of correct initial compilers
and a-posteriori program-checking [Goe-
rigk/Langmaack01b] are obeyed.
In the context of the Verifix-project
we will furthermore demonstrate how to
develop correct compiler generating tools
and how to incorporate even unverified
existing tools in a fully trusted and rigor-
ously proved correct manner [Heber-
le+98, Gaul+99, Gaul+96]. Moreover,
the specification and verification system
PVS [Owre+92] is used for mechanical
proof support, in particular for the for-
malization and verification of the compil-
ing specifications, and for providing sup-
port for high level compiler implementa-
tion verification using a transformational
approach.
In the following we want to focus
on how to develop a proved correct and
hence trustworthy initial compiler im-
plementation which we believe is the
foundational basis for the practical con-
struction of safe and secure, i.e. trustwor-
thy executable software.
4.1. Three Steps towards Fully
Correct Compilers. In his work on Piton's
verified translation [Moore88, Moore96] J
S. Moore recommends three steps in or-
der to present a convincing correctness
proof of a compiler written (or imple-
mented) in executable binary host ma-
chine code HML:
1. Specification of a compiling re-
lation C between abstract source and tar-
get languages SL and TL, and compiling
(specification) verification w.r.t. an ap-
propriate semantics relation ⊑ between
language semantics [[٠]] SL, [[٠]] TL.
2. Implementation of a correspond-
ing compiler program τHL in a high level
host language HL close to the specifica-
tion language, and high level compiler
implementation verification (w.r.t. C and
to program representations φSL
SL‘ and φTL
TL‘).
3. Implementation of a correspond-
ing compiler executable τHML written in
binary host machine language HML, and
low level compiler implementation verifi-
cation (with respect to [[ τHL ]] HL and pro-
gram representations φSL‘
SL‘‘ and φTL‘
TL‘‘ ).
If we work through every step,
then τHL resp. τHML is a correct or verified
compiler (implementation). If we want to
stress that a correctness proof has been
achieved even for a compiler executable
like τHML on a real processor, then we
sometimes call it fully correct (verified) as
informally explained before. Figure 2 in-
formally outlines the three essential steps
that we have to work through for the
construction and verification of fully cor-
rect compilers, and in particular of fully
correct initial compiler executables. We
will make everything shown in this dia-
gram precise in the following sections 5
and 6, and in particular we refer to sec-
tion 6.3.1, which discusses Figure 2 pre-
cisely.
5. Transformational Programs
We model the semantics of trans-
formational programs by partial relations
(or multivalued partial functions) f be-
tween input domains Di and (not neces-
Теоретические и методологические основы программирования
13
Fig 2. Three steps for correct compiler implementation τHML
sarily different) output domains Do. Thus,
a program semantics is a subset
f ⊆ Di × Do
which we often will write as f ∈ Di ⇀Do
(= 2 Di × Do) or as Di ⇀f Do; sometimes we
also use f : Di ⇀ Do. In case f is single-
valued, we may also use → instead of ⇀.
We use ";" to denote the well-known se-
mantical relational composition, i.e. if f1:
D1 ⇀ D2 and f2: D3 ⇀D4, then f1 ; f2 =def
=def{ (d1,d4) | ∃ d2 ∈ D2 ∩ D3 s.t. (d1,d2) ∈ f1
and (d2,d4) ∈ f2 } ∈ D1⇀D4. Data or ele-
ments are often program or memory
states or pairs of program and memory
states (sometimes called configurations
with control and data flow components)
which we simply call states as well.
Data in Di and Do are considered
regular or non-erroneous. In order to han-
dle irregular data, i.e. finite and infinite
errors, we assume that every data domain
D is extended by an individually associ-
ated disjoint non-empty error set Ω, i.e.
DΩ =def D ⊎ Ω
and D ∩ Ω = ∅. For every transforma-
tional program semantics f we assume an
extended version
f ∈ Di
Ω ⇀ Do
Ω
which we denote by the same symbol f
unless this will cause ambiguities. We
have Di
Ω = Di ⊎ Ωi and Do
Ω = Do ⊎ Ωo.
Errors are final. No computation
will ever recover from an error2. Thus, we
require (the extended) f to be error strict,
i.e. f to be total on Ωi and f (Ωi) ⊆ Ωo.
However, we have to respect a further
phenomenon. Errors are of essentially dif-
ferent types. They are either unavoidable
and we have to accept them, like for in-
stance machine resource violations, or
they are unacceptable and thus to be
avoided. We will allow unacceptable er-
rors to cause unpredictable (or chaotic)
consequences. In order to model this
phenomenon, we partition Ω in a non-
empty set A ⊆ Ω of acceptable and a non-
empty set U =def Ω \ A of unacceptable or
chaotic errors. So we require
Ωi = A i ⊎ Ui and Ωo = A o ⊎ Uo
and a strong error strictness, namely that f
is total on Ωi (and thus on Ai and Ui) and
f (A i) ⊆ A o and f (U i) ⊆ Uo .
The error sets Ω are supposed to
contain a particular standard error ele-
ment ⊥ which is to model infinite compu-
tation (divergence). So in particular we
have ⊥o ∈ Ωo, and for extended program
semantics f we additionally require
(d, ⊥o) ∈ f or equivalently ⊥o ∈ f(d) when-
ever there is a non-terminating (infinite)
computation of f starting with d ∈ Di
Ω.
2 Note that exceptions are not errors in
our sense. We think of exceptions as special
cases of non-local regular control flow.
Теоретические и методологические основы программирования
14
Thus, we model transformational
program semantics by strongly error strict
extended relations between extended in-
put and output domains, and we addi-
tionally require them to meet the above
condition for infinite computations.
5.1. Correct Implementation. Let fs
be a source and ft a target program se-
mantics. In the following we will explain
when ft correctly implements fs. This re-
quires data representation relations ρi ∈
Di
s Ω ⇀ D i
t Ω and ρo ∈ Do
s Ω ⇀ Do
t Ω between
source and target input and output data.
Both relations, ρi and ρo, and their in-
verses ρi
-1 and ρo
-1, have to be strongly
error strict (we sometimes call such ρ's
strongly error strict in both directions).
Fig 3. Source and target program semantics
fs, ft and data representations ρi, ρo
Definition 5.1. (Correct implemen-
tation or refinement) ft is said to be a cor-
rect implementation or refinement of fs
relative ρi and ρo and associated error
sets, iff
( ρi ; ft ) (d) ⊆ ( fs ; ρo) (d) ∪ Ao
t
holds for all d ∈ Di
s where fs (d) ⊆ Do
s ∪ Ao
s
(which is equivalent to ( fs ; ρo) (d) ⊆ Do
t ∪
∪Ao
t , because ρo is strongly error strict in
both directions).
For any target program computa-
tion, the outcome d'' in Do
t Ω is either an
acceptable error output in Ao
t, or there
exists a source program computation that
either ends in a (regular) d' correspond-
ing to d'' or with an unacceptable (cha-
otic) error output in Uo
s.
That is to say: If ft is a correct im-
plementation of fs, then ft either returns a
correct result, or an acceptable error, or,
if fs can compute an unacceptable error, ft
may (chaotically) return any result, be-
cause we do not require anything in that
case.
If ft correctly implements fs relative
ρi and ρo, we will write ρi ; ft ⊒ fs ; ρo or
even shorter just ft ⊒ fs (with a boldface
⊒). We indicate this diagram commuta-
tivity by the diagram in Figure 4 and we
will later see that we can compose cor-
rect implementation diagrams both verti-
cally and horizontally, which is a very
important fact for practical software en-
gineering and compiler generation.
Fig 4: Commutative diagram expressing
correct implementation
There are some variations of cor-
rect (relative) implementation as of Defi-
nition 1, which we would like to discuss:
We speak of correct acceptable imple-
mentation resp. of correct regular imple-
mentation or refinement, iff
∅ ≠ ( ρi ; ft )(d) ⊆ ( fs; ρo)(d) ∪ Ao
t acceptable
∅ ≠ ( ρi ; ft )(d) ⊆ ( fs ; ρo)(d) regular
holds for all d ∈ Di
s where ∅ ≠ fs (d) ⊆ Do
s ∪
∪Ao
s resp. ∅ ≠ fs (d) ⊆ Do
s. But note that –
in contrast to the different program cor-
rectness notions (cf. Section 5.1.1) – all
three implementation correctness notions
are independent; neither one implies the
other. It is remarkable, however, that
concrete correctness proofs turn out to be
of less complexity if ⊥ is supposed to be
unacceptable, i.e. if we prove variants of
correct regular implementation [Mueller-
Olm/Wolf00, Wolf00]. If ⊥ is supposed
acceptable, then our experience shows,
that we have to characterize greatest
fixed points exactly and to additionally
use computational or fixed point induc-
tion in order to prove variants of correct
acceptable implementation, e.g. preserva-
tion of partial correctness [Goerigk00a,
Goerigk00b].
5.1.1. Preservation of Relative
Correctness. It is an important observa-
Теоретические и методологические основы программирования
15
tion, that we can exactly characterize cor-
rect implementation by preservation of
relative correctness [Wolf00], which gen-
eralizes Floyd's and Hoare's notions of
partial respectively total program cor-
rectness. Let f ∈ Di
Ω ⇀ Do
Ω be a program
semantics and let Φ ⊆ Di and Ψ ⊆ Do be
predicates, i.e. subsets of regular data.
Definition 5.2. (Relative program
correctness) f is called (relatively) correct
with respect to (pre- and post-conditions)
Φ and Ψ (<Φ> f <Ψ> for short), iff
f (Φ) ⊆ Ψ ∪ Ao .
If there is no ambiguity, and if the
implicit parameters are clear from the
context, we will sometimes leave out the
word relative and simply speak of pro-
gram correctness. The following theorem
says that ft correctly implements fs if and
only if relative correctness of fs implies
relative correctness of ft for all pre- and
post-conditions Φ and Ψ.
Theorem 5.1. (Preservation of rela-
tive correctness) ft correctly implements fs
(ρi ; ft ⊒ fs ; ρo) if and only if, for all Φ ⊆ Di
s
and Ψ ⊆ Do
s,
<Φ> fs <Ψ> ⇒ < ρi(Φ) > ft < ρo(Ψ) >.
Proof. Only if: Let fs (d) ⊆ Do
s ∪ Ao
s imply
(ρi ; ft ) (d) ⊆ ( fs ; ρo ) (d) ∪ Ao
t for all d ∈ Di
s
and let fs (Φ) ⊆ Ψ ∪ Ao
s. Claim: ft (ρi(Φ)) ⊆
⊆ ρo(Ψ) ∪ Ao
t. In order to show this, let
d ∈ Φ. Then fs (d) ⊆ Ψ ∪ Ao
s ⊆ Do
s ∪ Ao
s.
Hence,
ft (ρi (d)) ⊆ ρo( fs (d)) ∪ Ao
t
⊆ ρo(Ψ ∪ Ao
s) ∪ Aot
= ρo(Ψ) ∪ Ao
t .
If: Let fs(Φ) ⊆ Ψ ∪ Ao
s imply
ft (ρi (Φ)) ⊆ ρo(Ψ) ∪ Ao
t for all Φ ⊆ Di
s and
Ψ ⊆ Do
s, and let fs (d) ⊆ Do
s ∪ Ao
s. Claim:
(ρi ; ft ) (d) ⊆ ( fs ; ρo) (d) ∪ Ao
t. For this, let
Φ =def {d} and Ψ =def fs (d) ∩ Do
s. Then
fs(Φ) = fs (d) = ( fs (d) ∩ Do
s ) ∪ ( fs (d) ∩ Ao
s ) ⊆
⊆Ψ ∪ Ao
s . So
(ρi ; ft )(d) ⊆ ρo( fs (d) ∩ Do
s ) ∪ Ao
t ⊆
⊆ ( fs ; ρo)(d) ∪ Ao
t .
Note that this theorem remains
valid even if we relax strong error strict-
ness; we actually need not require ρi and
ρo and their inverses to be total on error
sets. We only need that they respect the
partition in acceptable and unacceptable
errors. However, we still prefer data rep-
resentation relations to be total on error
sets (in both directions).
Again, we may discuss variations of
the notion of relative program correct-
ness, i.e. acceptable program correctness
resp. regular program correctness with
respect to pre-conditions Φ ⊆ Di and post-
conditions Ψ ⊆ Do:
<Φ> f <Ψ>acc iff ∅ ≠ f(d) ⊆ Ψ ∪Ao (acceptable)
<Φ> f <Ψ>reg iff ∅ ≠ f (d) ⊆ Ψ (regular)
respectively hold for all d ∈ Φ. Note that
regular program correctness implies ac-
ceptable program correctness, which im-
plies relative program correctness. Fur-
thermore, correct acceptable resp. regular
implementation is equivalent to preserva-
tion of acceptable resp. regular program
correctness, i.e. ft correctly acceptably
resp. regularly implements fs if and only if
<Φ> fs <Ψ>acc ⇒ <ρi (Φ)> ft <ρo (Ψ)>acc
(acceptable)
<Φ> f <Ψ>reg ⇒ <ρi (Φ)> ft <ρo (Ψ)>reg (regular)
respectively holds for all Φ ⊆ Di
s and
Ψ ⊆ Do
s.
5.1.2. Classical Notions of Correct
Implementation. In which sense does
relative or acceptable or regular program
correctness generalize the classical no-
tions of partial or total program correct-
ness? Let f be an original, i.e. unextended
program semantics
f ∈ Di ⇀Do
and let Φ ⊆ Di and Ψ ⊆ Do be pre- and
post-conditions, respectively. f is called
partially correct w.r.t. Φ and Ψ ({Φ} f {Ψ}
for short), if f (Φ) ⊆ Ψ. f is called totally
correct w.r.t. Φ and Ψ ([Φ] f [Ψ] for short),
if f is partially correct w.r.t. Φ and Ψ, i.e.
f (Φ) ⊆ Ψ, and additionally the domain
dom f of f comprises Φ, i.e. if additionally
dom f ⊇ Φ.
Теоретические и методологические основы программирования
16
Let us now choose the same par-
ticular error sets A = Ai = Ao =def {a} and
U = Ui = Uo =def {u} for both domains Di
and Do with ⊥ ∈ {a,u} and Ω = Ωi = Ωo =def
=def A⊎U, and extend f to f ext∈ Di
Ω⇀Do
Ω by
f ext =def f ∪ ((Di \ dom f ) × {⊥}) ∪ idΩ
f ext is strongly error strict, regardless of ⊥
being considered acceptable (Ai = Ao =def
=def {⊥}, Ui = Uo =def {u}) or unacceptable
(A i = Ao =def {a}, Ui = Uo =def {⊥}). dom(f ) =def
=def dom f is the domain of f.
Partial and Total Program Correct-
ness. Relative and acceptable correctness
are equivalent to partial correctness
<Φ> f ext <Ψ> ⇔ <Φ> f ext <Ψ>acc ⇔ {Φ} f {Ψ}
if ⊥ = a is considered acceptable, and
relative, acceptable and regular correct-
ness are equivalent to total correctness, if
⊥ = u is considered unacceptable:
<Φ> f ext <Ψ> ⇔ <Φ> f ext <Ψ>acc ⇔
⇔ <Φ> f ext <Ψ>reg ⇔ [Φ] f [Ψ]
Preservation of Partial and Total
Program Correctness. It is not only that
relative program correctness generalizes
classical partial and total program correct-
ness. Our notion of correct (relative) im-
plementation also generalizes well-known
implementation correctness notions.
Fig 5: Classical correct implementation
versus preservation of relative correctness.
Consider a classical unextended implementa-
tion diagram (a). If we extend fs and ft as ex-
plained before, and if we extend the data
representation relations ρi and ρo by ρi
ext =def
=def ρi ∪ idΩ respectively ρo
ext =def ρo ∪ idΩ as
well, then we get the extended diagram (b).
If we consider ⊥ acceptable, then
ρi
ext ; ft
ext ⊒ fs
ext ; ρo
ext ⇔ ρi ; ft ⊆ fs ; ρo
exactly expresses preservation of partial
program correctness. On the other hand,
if we consider ⊥ unacceptable, then
ρi
ext ; ft
ext ⊒ fs
ext ; ρo
ext ⇔
⇔ (ρi ; ft ) | dom( fs ; ρo) ⊆ fs ; ρo
and dom ρi ; ft ⊇ dom fs ; ρo
expresses exactly the classical preserva-
tion of total correctness.
Hence, it is justified to transfer the
terms total and partial to extended func-
tions or relations f ext, and we may use the
words ``correct total (resp. partial) imple-
mentation'' instead of "correct regular
(resp. relative) implementation". Also, we
may replace "regular (resp. relative) pro-
gram correctness" again by "total (resp.
partial) program correctness".
The classical software engineering
notion of correct implementation as
propagated in many (also formal) soft-
ware engineering approaches like for in-
stance in VDM (Vienna Development
Method) is preservation of total program
correctness. We should, however, keep in
mind that resources might well exhaust
while machine programs are executed on
real target machines, so that a compiled
program semantics ft can in general not
be proved to meet the requirements of
correct implementation in the latter
sense. Preservation of relative correctness
gives us the necessary means to define
adequate notions of correct implementa-
tion also for realistic correct compilation.
5.2. Composability. We men-
tioned that composability (transitivity) of
correct implementation is crucial for
modular software construction and verifi-
cation, and in particular for stepwise
compilation and compiler construction
and implementation. In the following we
prove vertical and horizontal transitivity,
i.e. that we may (vertically) decompose
correct implementations into steps (or
phases), and that correct implementation
distributes (horizontally) over sequential
(relational) composition. In both cases we
Теоретические и методологические основы программирования
17
will prove a more generally applicable
transitivity result as well.
Fig 6: Vertical composition expressed by
commutative diagrams: If the inner diagrams
are commutative, then so is the outer one.
Theorem 5.2. (Vertical transitivity
of correct implementation) If ft correctly
implements fs, and if ft‘ does so for ft ,
then ft‘ correctly implements fs.
Proof. Let Φ ⊆ Di
s, Ψ ⊆ Do
s and let
<Φ> fs <Ψ> . Then, due to Theorem 5.1,
we have <ρi(Φ)> ft <ρo(Ψ)> (commutativity
of the upper diagram) and <ρi' (ρi(Φ))> ft‘
<ρo' (ρo(Ψ))> (commutativity of the lower
diagram for pre-condition ρi (Φ) and post-
condition ρo(Ψ)). But the latter just means
<(ρi ; ρi') (Φ)> ft‘ <(ρo ; ρo') (Ψ)>
which completes the proof due to equiva-
lence of correct implementation and
preservation of (relative) correctness
(Theorem 5.1).
Theorem 5.3 (Horizontal transitivity
of correct implementation) If ft correctly
implements fs, and if ft‘ does so for fs‘,
then ft ; ft‘ correctly implements fs ; fs‘.
Fig 7: Horizontal composition expressed by
commutative diagrams: If the inner diagrams
are commutative, then so is the outer one.
Proof. Let
(1) ρi ; ft ⊒ fs ; ρo and
(2) ρo ; ft ⊒ fs ; ρo' and
(3) (fs ; fs‘ ) (d) ⊆ Do
s‘ ∪ Ao
s‘
Claim: (ρi ; ft ; ft‘)(d) ⊆ ( fs ; fs‘; ρo')(d) ∪
∪ Ao
t‘. Note that (f ; g)(d) = g(f (d)) and that
'';'' is associative and monotonic in both
arguments. By (3) we have fs‘(fs(d)) ⊆ Do
s‘ ∪
∪Ao
s‘ and by ((2), commutativity of the
right diagram) and associativity of '';'' we
get (ρo; ft‘)(fs(d)) ⊆ (fs‘ ; ρo') (fs(d)) ∪ Ao
t‘ and
hence
(4) ft‘((fs ; ρo)(d)) ⊆ (fs ; fs ; ρo')(d) ∪ Ao
t‘
and also
(5) ft‘((fs ; ρo)(d) ∪ Ao
t ) ⊆ ( fs ; fs‘; ρo')(d) ∪ Ao
t‘.
The latter holds by strong error
strictness of ft‘, i.e. ft‘ (Ao
t) ⊆ Ao
t‘, from (4).
By strong error strictness of fs‘ and (3) we
have fs(d) ⊆ Do
s ∪ Ao
s. Thus, by ((1), com-
mutativity of the left diagram) we get
(6) (ρi ; ft) (d) ⊆ ( fs ; ρo)(d) ∪ Ao
t
and finally, by monotonicity of relation
composition, (6) and (5) we get
(7) ft‘((ρi ; ft ) (d)) ⊆ ( fs ; fs‘ ; ρo')(d) ∪ Ao
t‘
which is nothing but our claim. An alter-
native equivalent calculation would be
(ρi ; ft ; ft‘)(d) = ft‘ ((ρi ; ft)(d)) ⊆ ft‘((fs ; ρo)(d) ∪
∪ Ao
t) ⊆ ft‘ ((fs ; ρo)(d)) ∪ Ao
t‘=
= (ρo ; ft‘)(fs (d)) ∪ Ao
t‘ ⊆ (( fs‘ ; ρo')( fs (d)) ∪
∪ Ao
t‘) ∪ Ao
t‘ = (fs ; fs‘ ; ρo')(d) ∪ Ao
t‘.
Unfortunately, we have to prove
horizontal transitivity in a different style.
A proof as elegant as for vertical com-
posability would require program seman-
tics, in particular ft‘, to be error strict in
both directions, which is of course not
the case in general. Note also that both
theorems would not hold if we would re-
lax the strong error strictness conditions
for data representations.
In practice we need more generally
applicable versions of both the vertical
and horizontal transitivity theorem. We
will often find intermediate input and
output data domains not to be exactly
the same.
Let, for vertical composition, com-
mutative inner diagrams and the outer
Теоретические и методологические основы программирования
18
diagram with its data representations
ρi ; ρi' and ρo ; ρo' be as in Figure 8.
Fig 8. Weak vertical composability: If the
inner diagrams are commutative and ft and ft‘‘
appropriately coincide, then the outer
diagram is commutative as well.
In order to ensure that ρi ; ρi' and
ρo ; ρo' are error strict in both directions,
we require the intermediate error sets to
agree, i.e. Ai
t = Ai
t‘‘, Ui
t = Ui
t‘‘, Ao
t = Ao
t‘‘, and
Uo
t = Uo
t‘‘. Furthermore, let
Ii
=def ρi(Di
s Ω) ∩ ρi' -1( ft -1(Do
t‘ Ω)) ⊆ Di
t Ω ∩ Di
t‘‘Ω
Io
=def Do
t Ω ∩ ρo' –1 (Do
t‘ Ω) ⊆ Do
t Ω ∩ Do
t‘‘ Ω
denote appropriate restrictions of domain
and codomain (on the intermediate level)
of input and output data representations,
respectively. Then, if ft contains ft‘‘ on
Ii
× Io , we can prove the following vertical
composition corollary:
Corollary 5.1. If the two inner dia-
grams of Figure 8 are commutative, if the
intermediate error sets agree, and if
ft |Ii
× Io
⊇ ft‘‘ |Ii
× Io
, then the outer diagram is
commutative as well.
Proof. Consider the following
(coupling) diagram:
Since ft |Ii
× Io
⊇ ft‘‘ |Ii
× Io
, it is im-
mediately clear that this diagram is
commutative. Thus, the outer diagram is
commutative due to vertical composition
Theorem 5.2.
For horizontal composition, let
commutative (inner) diagrams and the
outer diagram with sequential composi-
tions fs ; fs‘ respectively ft ; ft‘ be as in Fig-
ure 9. Again, for strong error strictness
reasons, we require the intermediate error
sets to agree, i.e. Ao
s = A i
s´, Uo
s = U i
s´,
Ao
t = Ai
t´, and Uo
t = U i
t´.
Fig 9: Weak horizontal composability: If the inner diagrams are
commutative and the data representations ρo and ρi' appropriately
coincide, then the outer diagram is commutative as well.
Let, again,
Is
=def fs(Di
s Ω) ∩ Di
s‘ Ω ⊆ Do
s Ω ∩ Di
s‘ Ω
It
=def ft (ρi(Di
s Ω)) ∩ ft‘ –1(Do
t‘ Ω) ⊆ Do
t Ω ∩ Di
t‘ Ω
denote appropriate restrictions of (inter-
mediate) domain and codomain of
source and target semantics, respec-
tively. Then, if the data representation
relation ρo is contained in ρi' on Is
× It
, we
can prove the following horizontal com-
position corollary:
Corollary 5.2. If the two inner dia-
grams of Figure 9 are commutative, if the
intermediate error sets agree, and if
ρo |Is
× It
⊆ ρi' |Is
× It
, then the outer diagram
is commutative as well.
Теоретические и методологические основы программирования
19
Proof. Consider the following
(coupling) diagram:
Since ρo |Is × It
⊆ ρi' |Is × It
, it is imme-
diately clear that this diagram is commu-
tative. Thus, the outer diagram is commu-
tative due to horizontal composition
Theorem 5.3.
Both more general theorems have
been proved by construction of commuta-
tive coupling diagrams. In both cases, we
have been looking for as weak as possible
conditions under which we are allowed to
compose commutative diagrams. Note,
however, that we might sometimes be able
to prove commutativity of more complex
diagrams from commutativity of constitu-
ent diagrams even under weaker assump-
tions. Note also, that we might be able to
prove correct implementation for a com-
posite diagram, even though one or more
component diagrams are not commutative.
Let us finally note, that every theo-
rem and corollary in this section does
hold for any of our notions of correct im-
plementation, i.e. not only for correct
relative (partial) implementation but also
for correct acceptable and correct regular
(total) implementation. We have defined
a family of correct implementation no-
tions which allows for more elaborated
and sophisticated adjustments to what-
ever the practical requirements for cor-
rect implementation really are. And the
essential (proof engineering) quality of
composability and hence modularizeabi-
lity is guaranteed for any choice.
6. Correct Compiler Programs
Main constituents of a program-
ming language are its set L of abstract
syntactical programs and its language
semantics [[٠]] L : L → Sem L, a partial
function from L into an associated seman-
tics space Sem L. The domain of [[٠]] L is
the set of so-called proper or well-formed
programs. In case of a well-formed π and
of sequential imperative programming
languages we are aiming at, [[π]] L can be
defined as a relation between extended
input and output data domains Di
L Ω and
Do
L Ω as discussed in the previous sections:
[[π]] L ∈ Sem L =def (Di
L Ω ⇀ Do
L Ω)
For a source language SL, a target
language TL and proper source programs
πs ∈ SL and πt ∈ TL with semantics
fs = [[πs]] SL and ft = [[πt]] TL, section 5 defines
the semantical relation ft ⊒ fs of correct
implementation:
Fig 10. Correct implementation for
sequential imperative programs
Data representations ρi and ρo and
associated acceptable and unacceptable
error sets are implicit parameters of ⊒.
Note also, that ⊒ implicitly defines if we
mean preservation of relative (partial),
acceptable or regular (total) correctness.
We have not yet fixed any one of these
parameters.
6.1. Compiling Specifications.
Every compiler program establishes a
mapping between source and target pro-
grams, actually between source and tar-
get program representations like for in-
stance character sequences on the one
and linkable object code format on the
other hand. In order to talk about this
mapping abstractly and to relate source
and target programs semantically, we as-
sume that we have or can define a com-
piling (or transformation) specification
C : SL ⇀ TL,
a mathematical relation between abstract
source and target programs. C might be
given by a closed inductive definition,
more or less constructive, or by a set of
Теоретические и методологические основы программирования
20
bottom-up rewrite rules to be applied by
a term or graph rewrite system (e.g. bot-
tom up rewrite systems, BURS [Pele-
gri/Graham88]) as for instance used in
rule-based code generators.
Fig 11. Correctness of the compiling
specification C
Definition 6.1 (Correct compiling
specification) We call C correct, if and
only if for any well-formed source pro-
gram πs ∈ SL, every associated target
program πt ∈ C(πs) is a correct implemen-
tation of πs, i.e. if and only if the diagram
in Figure 11 is commutative in the sense
([[٠]] SL
-1; C) ⊆ (⊑; [[٠]] TL
–1).
Note that we do not require C to
be defined for all well-formed SL-
programs, and we will also not require
this property for compiler program se-
mantics. Due to resource restrictions of
finite host machines we won't be able to
prove it for compiler programs, anyway,
because realistic source languages con-
tain arbitrarily large programs.
For any two programming lan-
guages SL and TL there is an implicitly
given natural correct compiling specifica-
tion that simply relates any well-formed
source program in SL to every of its cor-
rect implementations in TL:
ℂ =def [[ ٠]] SL ; ⊑ ; [[٠]] TL
–1
The following calculation shows,
that ℂ is correct (Actually, if we only
consider well-formed programs, it is the
largest correct compiling specification.):
([[٠]] SL
–1 ; ℂ) =
= ([[٠]] SL
–1 ; [[٠]] SL
; ⊑ ; [[٠]] TL
–1) ⊆ (⊑; [[٠]] TL
–1).
But how is a correct C related to ℂ
in general? Of course, ℂ ⊈ C (C might
even be empty, e.g. for the pathological
compiler which fails on every source pro-
gram). Restricted to well-formed source
programs, C is a subset of ℂ. However, in
general C might relate non well-formed
SL-programs (which have no semantics)
to TL-programs. Perhaps well-formedness
is hard to decide or even undecidable. So
compilers sometimes generate or have to
generate target code also for improper
source programs without explicitly sig-
naling an error. The user should be care-
ful, keep this in mind and avoid non-
well-formed compiler inputs. In any case,
in general C ⊈ ℂ as well.
Hence, so far C is unrelated to ℂ,
and so will be any correct implementa-
tion of C. This observation suggests to
view at the program sets SL and TL as
data domains and extend them by par-
ticular unacceptable error elements. This
will allow us to also formally express in
particular the well-formedness precondi-
tion that source programs have to fulfill if
they are to be correctly compiled. We
will do so also for the semantics spaces
SemSL and Sem TL .
For SLΩ and TLΩ we need an unac-
ceptable error nwf (for "non-well-formed")
in USL and UTL, and for SemSL
Ω and
SemTL
Ω
we need an unacceptable error
uds (for "undefined semantics") in USemSL
and USemTL. C, ℂ, [[٠]] SL, [[٠]] TL and ⊑ are
extended so that these artificial error ele-
ments are related to each other and to
non-well-formed programs in SL and TL.
Again we denote the extended relations
by the same symbols.
Observe in Figure 12 (b), that we
used ⊒v to indicate the difference be-
tween (horizontal) correct implementation
⊒ and (vertical) correct compiler imple-
mentation ⊒v (see section 6.3.3). For ⊒v
(respectively ⊒v) only preservation of
relative (partial) correctness makes sense
in practice, i.e. commutativity of diagram
(b) is only valid if ⊒v expresses correct
relative (partial) implementation.
Теоретические и методологические основы программирования
21
Fig 12. Correctness of extended compiling
specifications. The original diagrams (a) (for
C and ℂ) are commutative if and only if the
corresponding extended diagrams (b) are.
The extended C is a correct im-
plementation of the extended ℂ (Figure
13) and hence this step homogeneously
fits on top of a stack of further commuta-
tive diagrams establishing correct trans-
formation and implementation steps, all
correctly tied together and related to ℂ
by vertical composability due to Theorem
5.2 and Corollary 5.1 from section 5. As
any compiler program, also the compiling
specification C reflects design decisions.
It already selects particular target pro-
grams from the set of all possible correct
implementations.
Fig 13. Correctness definition for
extended compiling specifications
Theorem 6.1 (Correct compiling
specifications) A compiling specification
C is correct, if and only if it is a correct
implementation of ℂ.
Proof: If: by Figure 13, Figure 12
(b) and vertical composition.
Only if: Let πs ∈ SL and ℂ (π s) ⊆
⊆TL ∪ ATL (*), and let πt ∈ C(πs). We have
to show: πt ∈ ℂ(πs) ∪ ATL. First note that
πs is well-formed, i.e. has semantics
[[ πs]] SL ∈ SemSL, because otherwise πt and
ℂ(πs) would be the unacceptable error
nwf ∉ TL ∪ ATL which contradicts (*). If
πt ∈ ATL, then we are done. πt ∈ UTL is
impossible, because πt would be nwf and
hence πs not well-formed.
So let πt ∈ TL. Then, ([[ πs]] SL, πt) ∈
∈ ([[٠] SL
–1 ; C). Due to correctness of C
(Figure 12 (a)) we have ([[ πs]] SL, πt) ∈
∈ (⊑; [[٠]] TL
–1), that is to say (πs, πt) ∈
∈ ([[٠]] SL ; ⊑ ; [[٠]] TL
—1). But the latter is
exactly the definition of ℂ, hence we
have πt ∈ ℂ(πs).
6.2. Correct Compiler Programs. In
order to prove that a compiler program
(sometimes also called compiler
implementation or simply compiler) is
correct, we want to relate its semantics
to the compiling specification. It is often
a good advice to write a compiler in its
own source language. In general,
though, the compiler will be imple-
mented in a high level or a low level
machine host language HL with seman-
tics space
SemHL
Ω = (Di
HL Ω ⇀ Do
HL Ω )Ω.
If we want to call an HL-program τh
a compiler from SL to TL, then we need
representation relations φs and φt to rep-
resent SL- and TL-programs as data in
SL´ Ω =def Di
HL Ω resp. in TL´Ω =def Do
HL Ω.
Note that there are a lot of data in SL´
and TL´ which do not represent pro-
grams, but for a consistent presentation
we prefer to let a compiler program τh
just be like any other HL-program.
The situation is as described in
Figure 14. However, in order to treat lan-
guages of concrete program repre-
sentations like SL´ and TL´ as reasonable
programming languages, we require that
[[٠]] SL´ =def φs
–1 ; [[٠]] SL and [[٠]] TL´ =def
=def φ t
–1 ; [[٠]] TL are single-valued partial
functions. Thus, any concrete representa-
tion of a well-formed SL- or TL-program
has a unique semantics.
Теоретические и методологические основы программирования
22
Fig 14. Compiler programs related to compil-
ing specifications. If the lower diagram is
commutative as well, we call τh a correct
compiler program
Definition 6.2 (Correct compiler
program) We call τh a correct compiler
program, iff [[τh]] HL ⊒ ℂ, i.e. iff [[τh]] HL is a
correct implementation of ℂ.
If τh is a correct compiler, then the
lower diagram of Figure 14 and, due to
vertical composition, also the outer dia-
gram is commutative. Actually, we could
equivalently have required ⊒-commuta-
tivity of the outer diagram. This would
entail commutativity of both inner dia-
grams and in particular of the lower dia-
gram (the upper diagram is commutative
anyway).
The proof of the latter remark is a
bit more detailed, but analogous to that
of Theorem 6.1: Let πs ∈ SL and φt (ℂ(πs)) ⊆
⊆ TL´ ∪ ATL´ (*), and let π't ∈ [[πs]] SL(φs (πs)).
We have to show π't ∈ φt(ℂ(πs)) ∪ ATL´.
First note that πs is well-formed, i.e. has
semantics [[πs]] SL. Otherwise, ℂ would as-
sign nwf ∈ UTL to πs which contradicts (*).
If π't ∈ ATL´ , we are done. If π't ∈ UTL´,
then by commutativity of the outer dia-
gram [[πs]] SL∈ (⊑; [[٠]] TL´
–1)–1 (UTL´) = {uds}
contradicting well-formedness of πs. So
let π't ∈ TL´. Commutativity of the outer
diagram means ([[٠]] SL´
–1 ; [[τh]] HL)([[πs]] SL) ⊆
⊆ (⊑; [[٠]] TL´
–1)([[πs]] SL) ∪ ATL´ and therefore
π't ∈ (⊑; [[٠]] TL´
–1)([[πs]] SL) = φt([[٠]] TL
—1 (⊑
⊑ ([[πs]] SL))). Since π't and [[πs]] SL are regu-
lar in TL´ resp. SemS, we have π't ∈
∈ φt (ℂ(πs)) by definition of ℂ.
Any correct compiler program τh in-
duces an associated correct extended com-
piling specification Cτ =def (φs ; [[τh]] HL ; φt
–1) :
SLΩ ⇀ TLΩ such that
[[ τh ]] HL ⊒ C τ ⊒ ℂ .
If [[τh]] HL is a correct implementa-
tion of any correct specification C, i.e.,
[[ τh ]] HL ⊒ C ⊒ ℂ, then τh is a correct
compiler program (cf. Figure 15). That is
to say: A compiler program is correct, if
and only if it is the correct implementa-
tion of a correct compiling specification.
Fig 15. Compiler programs and compiling
specifications. Due to vertical composition, a
correct implementation of a correct compil-
ing specification is a correct compiler
But what does happen, if we apply a
correct compiler program to the represen-
tation of a well-formed source program? It
should not be a surprise, that we will get
at most a representation of a correct im-
plementation of the source program:
Theorem 6.2. Let τh be a correct
compiler program and let π's ∈ φs(πs) be
the representation of a well-formed
SL-program. Then any regular π't ∈
∈ [[τh]] HL(π's) represents a correct imple-
mentation πt of πs.
Proof: Since πs is well-formed,
ℂ(πs) ⊆ TL and hence, since τh is a correct
compiler program, we have (φs ; [[τh]] H L)(πs) ⊆
⊆ (ℂ;φt) (πs) ∪ Ao
HL. Thus,
π't ∈ [[ τh ]] HL (π's) ⊆ [[ τh ]] HL (φs(πs)) ⊆
⊆ (ℂ;φt) (πs) ∪ Ao
HL .
Теоретические и методологические основы программирования
23
But π't is regular, i.e. π't ∉ Ao
HL. Therefore,
π't ∈ (ℂ;φt) (πs). So π't ∈ φt(πt) for a πt ∈
∈ ℂ(πs), which means [[πt]] TL ⊒ [[πs]] SL.
Let us call a concrete SL´- or TL´-
datum π's or π't a well-formed SL´- or TL´-
program, if it represents a well formed
SL- or TL-program. Then π's or π't have
semantics [[π's]] SL´ respectively [[π't]] TL´.
Thus, it is defined when π't correctly im-
plements π's. According to Theorem 6.2,
every regular result π't ∈ [[ τh ]] HL (π's) of a
correct compiler τh, applied to a well-
formed π's, correctly implements π's.
That is to say: A correct compiler,
applied to a well-formed source program,
returns at most correct implementations
of that source program.
6.3. Discussion and First Sum-
mary. We want to summarize some im-
portant observations and give some addi-
tional explanations. In particular, we will
relate the definitions and notions defined
in the previous sections to our informal
sketch of a conscientious compiler cor-
rectness proof as of section 4.1 and in
particular of Figure 2. Moreover, we will
discuss McKeeman's T-diagram notation,
give some remarks on the difference be-
tween correct implementation of user
programs and of compiler programs, and
finally we want to discuss correct imple-
mentation for optimizing compilers.
6.3.1. Precise View at the Three
Steps. Let us first come back to the dia-
gram shown in Figure 2 (page 13) in sec-
tion 4.1. In the previous sections (5, 6.1
and 6.2) we have exactly defined every
single notion mentioned in section 4.1
and, hence, we now know precisely every
conjecture we have to prove in order to
implement an SL to TL compiler correctly
as an executable program on a host
processor HM.
In Figure 2, every data set, pro-
gram set and semantics space, every pro-
gram semantics, data representation, pro-
gram representation, semantics function,
compiling specification, compiler seman-
tics and semantics relation has to be ap-
propriately extended by unacceptable
and acceptable error elements. The fol-
lowing commutative diagrams (Figure 16
and 17) precisely express that C is a cor-
rect compiling specification, and that τHL
respectively τHML are correct compiler
programs.
Programs and their representations
have equal semantics. But we should ex-
plicitly note that in diagram 16 the com-
piler program τHML is not a representa-
tion of τHL. These two programs have in
general different semantics, but the for-
mer is a correct implementation of the
latter.
Fig 16. This diagram is again illustrating the three steps for correct
compiler implementation as of Figure 2 on page ??
Теоретические и методологические основы программирования
24
Fig 17. This diagram is again illustrating
correct implementation as of Figure 4 on
page ??. Note that [[πSL]] SL = [[π'SL]] SL´ =
= [[π''SL]] SL´´ and analogously for TL
6.3.2. T-Diagram Notation. McKee-
man's so-called T-diagrams allow to illus-
trate the effects of iterated compiler ap-
plications in an intuitive way. We use
them as shorthand notations for particu-
lar diagrams as of Figure 18.
Fig 18. The situation which we will abbrevi-
ate by McKeeman's T-diagrams
Recall that ℂ is the natural correct
compiling specification from SL to TL.
Well-formed programs and their (syntac-
tical) φ-representations have equal se-
mantics, and τHL´ ∈ φHL
HL´(τHL) is a well-
formed HL´-program compiling syntacti-
cal SL´-programs to syntactical TL´-
programs. HL´ is the domain of perhaps
more concrete syntactical representations
of HL-programs. In this situation we use
T-diagram (Figure 19) as an abbreviation
for the diagram in Figure 18. However,
we have to keep in mind that the con-
crete situation is a bit more involved,
Fig 19. McKeeman's T-diagram as a
short-hand for the above situation
that the T-diagrams do not explicitly ex-
press crucial differences between various
program representations. We need to dis-
tinguish programs, program semantics
and (syntactical) program representations
in order to suffice requirements from
practice. We cannot put practitioners
short by elegant but too nebulous ideali-
zations.
6.3.3. Correct Implementation ver-
sus Correct Compiler Implementation. If
we bootstrap compiler programs, we have
in general to distinguish between two dif-
ferent notions of correct implementation.
Source programs are to be correctly im-
plemented by target programs (relating
source to target programs) on the one
hand, and the compiler itself is to be cor-
rectly implemented on the host machine
(which relates the compiler source pro-
gram to the compiler machine program).
Error behavior and required
parameterization of application programs
πSL, πTL and their representations πSL´, πTL´
, πSL´´ , πTL´´ are in general of a different
nature and independent of the expected
error behavior and required parameteriza-
tion for the compiler, i.e. for the specifi-
cation C and compiler programs τHL, τHML
and their syntactical representations.
For instance, let us assume SL to
be a process programming language. The
process programmer would not like to
witness any uncertainty nor error at com-
putation time of source programs πSL re-
spectively πSL´, πSL´´. That is source pro-
grams are written such that
∅ ≠ [[πSL]] SL (di
s) ⊆ Dos (1)
holds whenever πSL is applied to an input
di
s ∈ Di
s \ [[πSL]] SL
-1 (Uo
s) outside the domain
of computations which possibly end in
unacceptable errors. But this involves
regular termination and hence total cor-
rectness of πSL which the process pro-
grammer requires to be preserved for
any correct implementation πTL. He/she
wants that
∅ ≠ [[ πTL]] TL (di
t) ⊆ Dot (2)
Теоретические и методологические основы программирования
25
holds whenever the target program πTL is
applied upon the representation di
t ∈ ρi(di
s ),
di
s ∉ [[πSL]] SL
-1(Uo
s), of the corresponding
input. Correct regular (total) implementa-
tion together with (1) guarantees (2), be-
cause due to section 5.1, we have
∅ ≠ [[ πTL]] TL(di
t) ⊆ ρo( [[ πSL]] SL(di
s)) ⊆ Dot.
On the other hand, the same proc-
ess programmer will (and in general has
to) accept compile time error reports, like
for instance HM-memory overflow, while
πSL is compiled to πTL, i.e. while the com-
piler machine implementation τHML is
executed and applied upon a (syntactical)
representation πSL´´ of the source program
πSL. With respect to compilation, the
process programmer wants a guarantee at
execution time of πTL´´ whenever τHML has
succeeded on HM and has generated the
target program representation πTL´´, which
means that (2) is established by success-
ful execution of the compiler implemen-
tation τHML.
Note that there are no obvious
natural mappings between the error sets
Ao
s, Uo
s , Ao
t, Uo
t crucial for the correct im-
plementation of source programs by tar-
get programs on the one hand, and the
error sets ATL´ =def Ao
HL, UTL´ =def Uo
HL,
ATL´´ =def Ao
HML and UTL´ =def Uo
HML crucial
for the correct implementation notion for
generating the compiler machine execu-
table τHML on the other hand. We have to
distinguish these two correct implementa-
tion relations.
6.3.4. Notes on Optimizing Com-
pilers. As already mentioned, many exist-
ing and in particular optimizing compiler
programs τh do not check all pre condi-
tions necessary for correct compilation of
source programs. In particular optimizing
transformations often need pre-conditions
which, for practical reasons, are too hard
to decide or are even algorithmically un-
decidable 3. Therefore, in general compil-
3 For many programming languages it is algo-
rithmically undecidable whether or not for in-
stance variables are initialized before they are
used, or if programs terminate regularly.
ing specifications C or compiler program
semantics [[ τh ]] HL might yield unreason-
able target programs even for well-
formed programs for which additional op-
timization pre-conditions do not hold.
Our more elaborated view at cor-
rect implementation offers a remedy
which exploits the notion of acceptable
errors in ATL. Let us think of a compiler
warning (like for instance "Warning: ar-
ray index check omitted in line ...") as a
potential error message, i.e. as an indica-
tion for an eventually generated target
program πt to potentially belong to the
set of acceptable errors in ATL in the fol-
lowing sense: ''We [the compiler] give
you [the compiler user] the following tar-
get program πt, but it contains optimiza-
tions which require additional pre condi-
tions Φ ⊆ Di
s for your source program to
hold. If you cannot guarantee Φ, please
take this as an error message, because πt
might not be correct.''
That is to say: Besides the usual
compiling specification C every source
program πs carries an additional (optimi-
zation) pre-condition Φ = PC(πs) ⊆ Di
s,
PC : SL → 2Dis, which leads to a modified
source language semantics
[[ πs]] SL,PC =def [[ πs]] SL ∪ (Dis\PC(πs)) × {pcf},
where pcf ∈ Uo
s reads as "(optimization)
pre-condition false". Now, if compiling
specification or compiler program deliver
a target program together with an opti-
mization warning, then this guarantees a
weaker correct implementation of πs by
πt, namely that
(ρi ; [[ πt]] TL) (di
s ) ⊆ ([[ πs]] SL; ρo) (di
s) ∪ Aot
holds for all di
s ∈ PC(πs) with [[ πs]] SL(di
s ) ⊆
⊆ Di
s ∪ Ao
s. This weaker notion of correct
implementation (with respect to [[٠]] SL)
can equivalently be expressed by usual
correct implementation, but with respect
to the weaker semantics relation [[٠] SL,PC .
A well-known optimization is the
so-called redundant (dead) code elimina-
tion, which might violate preservation of
relative (partial) correctness, e.g. which
might eliminate the code that for some
Теоретические и методологические основы программирования
26
input data di
s ∈ Di
s would cause a runtime
error like for instance a division by zero.
The source program πs might be partially
(relatively) correct w.r.t. some pre- and
post-conditions Φ´ resp. Ψ´, whereas the
optimized target program πt is not. It
might return a regular but incorrect re-
sult if applied to di
t ∉ ρi (Φ). If the addi-
tional optimization pre condition Φ does
not hold for the input, πt might danger-
ously deceive the user. Its result might
have nothing in common with any regu-
lar source program result do
s
.
A different optimization is the so-
called unswitching, which might violate
preservation of total (regular) correctness.
Unswitching is an optimization that
moves conditional branches outside loops
and in particular changes the sequential
order of conditional expressions while
transforming
while(b, if (c, π1,π2)) ↦ if (c, while (b, π1),
while (b, π2)) .
This transformation does in general
not preserve regular (total) correctness. A
process programmer, who has proved
regular (total) correctness of a source
program πs (containing the left statement)
would dangerously be cheated by the
program πt (containing an implementation
of the right statement instead) if πt is ap-
plied to input data di
t ∉ ρi (Φ) such that b
evaluates to false and c causes a runtime
error. In that case, πt would incorrectly
irregularly abort with an error, which
might lead to a dangerous situation if πt
controls for instance a safety critical
process.
7. From Correct Compiler Programs to
Trusted Compiler Implementations
At this point we have developed a
mathematical theory of expressing com-
piling and compiler implementation cor-
rectness in a compositional, rigorous and
realistic way using special commutative
diagrams. In particular Figure 16 on page
23 precisely defines the three essential
proof obligations corresponding to the
three tasks necessary in order to provide
a rigorous and conscientious correctness
proof for an initial trusted compiler ex-
ecutable.
It is the machine (low) level com-
piler implementation correctness proof by
bootstrapping and a-posteriori code in-
spection, which is new and for the first
time closes the implementation gap rig-
orously and trustworthily. It needs further
explanation. Therefore, the forthcoming
second part of our article on Trusted
Compiler Implementation [Goerigk/Lang-
maack01b] will go into detail on this
proof for the initial trusted compiler ex-
ecutable which we have constructed and
completely verified. The article will also
give a security related motivation for low
level implementation verification and
show that otherwise correctness and thus
trustworthiness cannot be guaranteed.
For machine level compiler imple-
mentation verification we will use a spe-
cialized bootstrapping technique with a-
posteriori code-inspection. Initially, a
Common Lisp system runs on and gener-
ates code for our compiler on an auxil-
iary processor. We use it as an unverified
compiler generator which transforms its
specification (the compiler source pro-
gram) and generates an (auxiliary) com-
piler machine executable. The generated
executable depends on untrusted auxil-
iary software and is not verified. Its re-
sults have to be checked. Fortunately, we
need to use this auxiliary executable only
once. N. Wirth's technique of writing the
compiler in its own source language en-
ables to bootstrap the compiler source
again, and this run, if successful, gener-
ates a target program which should be
the specified target code for the com-
piler. Although in general every result of
the auxiliary executable would have to be
checked, we need a-posteriori result
checking only for exactly one run.
This is because we realize an im-
portant difference to the general proce-
dure: As soon as the syntactical check
succeeds and guarantees, that the gener-
ated binary is as specified by the seman-
tically correct compiling specification, a
semantics to syntax reduction theorem
applies and guarantees that the gener-
Теоретические и методологические основы программирования
27
ated binary is a (semantically) correct
compiler executable on the target ma-
chine. Compiling specification verifica-
tion guarantees, that specification com-
pliance implies semantical correctness.
Source and intermediate languages
for the initial compiler are carefully cho-
sen in order to be able to finally produce
a convincing complete rigorous proof
document. They have particularly been
chosen to isolate crucial compilation
steps and to enable code inspection by
target to source code comparison.
The compiler will horizontally be
decomposed in a (sequential) composi-
tion of subsequent passes. Vertical com-
position originates from horizontal com-
position: The compiler generates a tower
of subsequent intermediate programs of
decreasing abstraction level between
high-level source and machine level tar-
get program. Each step (pass) corre-
sponds semantically to a commutative
diagram expressing that the lower-level
intermediate program correctly imple-
ments the higher-level program.
For the initial compiler every in-
termediate program representation is
made explicit. Every intermediate lan-
guage has an explicit composition opera-
tor expressing the (horizontal) sequential
composition of passes. If the compiler is
applied to itself, then every compiler pass
explicitly transforms step by step the se-
quential composition of n (= 4) passes to
again a sequential composition of n
passes. The process finally corresponds
semantically to an n by n matrix of com-
mutative diagrams (actually n+1 by n in-
cluding the specification on top),
plugged together by horizontal and verti-
cal composition theorems.
Semantical machine code inspec-
tion – to semantically understand and to
assure the correctness of generated target
code – is tedious, cumbersome, error-
prone and probably unmanageable. But
also syntactical machine level code in-
spection, i.e. to compare source and ex-
pected low-level machine code with re-
spect to the (correct) compiling specifica-
tion, is cumbersome and should and can
be further minimized. Horizontal and ver-
tical composition with only two small low
level transformations will split the code
inspection task in a number of small and
easier parts. Lowest level machine code
inspection is only necessary for the final
code generation. Moreover, the boot-
strapping process can already make use
of checked lower level passes to guaran-
tee implementation correctness for higher
level intermediate code, which further
helps saving much and in particular low
level machine code inspection below the
diagonal of the matrix mentioned above.
The initial ComLisp compiler uses
five subsequent passes including front
end and code generation. They are by no
means arbitrary. Front end, transforma-
tion of recursive procedures using stack
technique, of recursive data types imple-
mented on a heap memory, of control
structure to linear machine code, and
code generation producing binary execu-
table code, all these passes coincide with
passes identifiable also in compilers in
general. They also adequately modularize
the theorem prover supported mechanical
proof of compiling correctness.
Acknowledgments We would like
to thank our colleagues in the Verifix
project for many fruitful discussions, in
particular Axel Dold, Thilo Gaul, Gerhard
Goos, Andreas Heberle, Friedrich von
Henke, Ulrich Hoffmann, Vincent Via-
lard, Wolf Zimmermann. Special thanks
to Markus Müller-Olm and Andreas Wolf
for their contributions to the notion of
relative program correctness and its pre-
servation.
[Abrial+91] J.R. Abrial, M.K.O. Lee, D.S. Neilson,
P.N. Scharbach, and I.H. Sørensen. The B-method.
In VDM'91: Formal Software Development Methods
Volume 2, volume 552 of LNCS, pages 398—405.
Springer-Verlag, 1991.
[Bauer78] F.L. Bauer. Program development by
stepwise transformations – the project CIP. In
F. L. Bauer and M. Broy, editors, Program
Construction, volume 69 of Lecture Notes in
Computer Science, pages 237—266. Springer
Verlag, 1978.
[Blum+89] M. Blum, M. Luby, and R. Rubinfeld.
Program result checking against adaptive pro-
grams and in cryptographic settings. In DIMACS
Workshop on Distributed Computing and Cryp-
thography, 1989.
Теоретические и методологические основы программирования
28
[Boerger/Rosenzweig92] E. Börger and D. Rosen-
zweig. The WAM-definition and Compiler Cor-
rectness. Technical Report TR-14/92, Dip. di In-
formatica, Univ. Pisa, Italy, 1992.
[Broy92] M. Broy. Experiences with software
specification and verification using LP, the larch
proof assistant. Technical Report 93, Digital Sys-
tems Research Center, Palo Alto, July 1992.
[Boerger/Schulte98] E. Börger and W. Schulte.
Defining the Java Virtual Machine as Platform for
Provably Correct Java Compilation. In 23rd Inter-
national Symposium on Mathematical Foundations
of Computer Science, LNCS. Springer, 1998.
[BSI94] BSI – Bundesamt für Sicherheit in der
Informationstechnik.BSI-Zertifizierung. BSI 7119,
Bonn, 1994.
[BSI96] BSI – Bundesamt für Sicherheit in der
Informationstechnik}. OCOCAT-S Projektauss-
chreibung, 1996.
[Chirica/Martin86] L. M. Chirica and D. F. Mar-
tin. Toward Compiler Implementation Correctness
Proofs. ACM Transactions on Programming Lan-
guages and Systems, 8(2):185—214, April 1986.
[Curzon93a] P. Curzon. Deriving Correctness
Properties of Compiled Code. Formal Methods in
System Design, 3:83-115, August 1993.
[Curzon94] P. Curzon. The Verified Compilation of
Vista Programs. Internal Report, Computer Labora-
tory, University of Cambridge, January 1994.
[Dijkstra76] Edsger W. Dijkstra. A Discipline of
Programming. Prentice-Hall, 1976.
[Dold00] Axel Dold. Formal Software Development
using Generic Development Steps. Logos-Verlag,
Berlin, 2000. Dissertation, Universität Ulm.
[Fagan86] M. E. Fagan. Advances in software in-
spections. IEEE Transactions on Software Engi-
neering, SE-12(7):744-751, 1986.
[Flatau92] A. D. Flatau. A verified implementation
of an applicative language with dynamic storage
allocation. PhD thesis, University of Texas at Aus-
tin, 1992.
[Garland/Guttag91] S.J. Garland and J.V. Guttag.
A guide to lp, the larch prover. Technical Report
SRC Report 82, Digital Systems Research 'Center,
1991.
[Gaul+96] Th. Gaul, G. Goos, A. Heberle,
W. Zimmermann, and W. Goerigk. An Architec-
ture for Verified Compiler Construction. In Joint
Modular Languages Conference JMLC'97, Linz,
Austria, March 1997.
[George+92] C. George, P. Haff, K. Havelund,
A. E. Haxthausen, R. Milne, C. B. Nielson,
S. Prehn, and K. R. Wagner. The Raise Specifica-
tion Language. Prentice Hall, New York, 1992.
[Goerigk/Langmaack01] W. Goerigk and
H. Langmaack. Compiler Implementation Verifi-
cation and Trojan Horses. In D. Bainov, editor,
Proc. 9th International Colloquium on Numerical
Analysis and Computer Science with Applications,
Plovdiv, Bulgaria, 2001.
[Goerigk/Langmaack01a] W. Goerigk and
H. Langmaack. Compiler Implementation Verifica-
tion and Trojan Horses (Extended Draft Version).
Technical report, Institut für Informatik, CAU,
2001. Available under http://www.informatik.uni-
kiel.de/~wg/Berichte/Plovdiv.ps.
[Goerigk/Langmaack01b] W. Goerigk and
H. Langmaack. Will Informatics be able to Justify
the Construction of Large Computer Based Sys-
tems? Part II: Trusted Compiler Implementation.
International Journal on Problems in Program-
ming, 2002. Forthcoming.
[Goerke96] W. Goerke. Über Fehlerbewußtseins-
kultur. Mündlicher Diskussionsbeitrag, Informatik-
Kolloquium, IBM, Böblingen, 1996. Unpublished,
1996.
[Goerigk99a] W. Goerigk. On Trojan Horses in
Compiler Implementations. In F. Saglietti and
W. Goerigk, editors, Proc. des Workshops Sicher-
heit und Zuverlдssigkeit softwarebasierter Systeme,
ISTec Report ISTec-A-367, ISBN 3-00-004872-3,
Garching, August 1999.
[Goerigk99b] W. Goerigk. Compiler Verification
Revisited. In M. Kaufmann, P. Manolios, and J S.
Moore, editors, Computer Aided Reasoning: ACL2
Case Studies. Kluwer Academic Publishers, 2000.
[Goerigk00a] W. Goerigk. Trusted Program Exe-
cution. Habilitation thesis. Techn. Faculty, Chris-
tian-Albrechts-Universität zu Kiel, May 2000. To
be published.
[Goerigk00b] W. Goerigk. Proving Preservation of
Partial Correctness with ACL2: A Mechanical
Compiler Source Level Correctness Proof. In M.
Kaufmann and J S. Moore, editors, Proceeding of
the ACL2'2000 Workshop, University of Texas,
Austin, Texas, U.S.A., October 2000.
[Gurevich91] Y. Gurevich. Evolving Algebras;
A Tutorial Introduction. Bulletin EATCS, 43:264-
284, 1991.
[Gurevich95] Y. Gurevich. Evolving Algebras:
Lipari Guide. In E. Börger, editor, Specification and
Validation Methods. Oxford University Press, 1995.
Теоретические и методологические основы программирования
29
[Gaul+99] Th. Gaul, W. Zimmermann, and
W. Goerigk. Construction of Verified Software Sys-
tems with Program-Checking: An Application To
Compiler Back-Ends. In A. Pnueli and P. Traverso,
editors, Proc. FLoC'99 International Workshop on
Runtime Result Verification, Trento, Italy, 1999.
[Heberle+98]A. Heberle, Th. Gaul, W. Goerigk,
G. Goos, and W. Zimmermann. Construction of
Verified Compiler Front-Ends with Program-Che-
cking. In Proceedings of {PSI} '99: Andrei Ershov
Third International Conference on Perspectives Of
System Informatics, volume 1755 of Lecture Notes
in Computer Science, Novosibirsk, Russia, 1999.
Springer Verlag.
[Hoare+93] C. A. R. Hoare, He Jifeng, and
A. Sampaio. Normal Form Approach to Compiler
Design. Acta Informatica, 30:701-739, 1993.
[Hoffmann/Krieg-Brueckner93] B. Hoffmann and
B. Krieg-Brückner. Program Development by Speci-
fication and Transformation. Springer, Berlin, 1993.
[HSE01] C. Jones, R.E. Bloomfield, P.K.D. Fro-
ome, and {P.G.} Bishop. Methods for assessing
the safety integrity of safety-related software of
uncertain pedigree (SOUP). Contract Research
Report 337/2001, Health and Safety Executive,
Adelard, London, UK, 2001.
[Jones90] C. B. Jones. Systematic Software Devel-
opment Using VDM, 2nd ed. Prentice Hall, New
York, London, 1990.
[Kaufmann/Moore94] M. Kaufmann and J S. Mo-
ore. Design Goals of ACL2. Technical Report 101,
Computational Logic, Inc., August 1994.
[Langmaack73] H. Langmaack. On Correct Pro-
cedure Parameter Transmission in Higher
Programming Languages. Acta Informatica,
2(2):110-142, 1973.
[Langmaack97a] H. Langmaack. Softwareenginee-
ring zur Zertifizierung von Systemen: Spezifika-
tions-, Implementierungs-, Übersetzerkorrektheit.
Informationstechnik und Technische Informatik
it+ti, 39(3):41—47, 1997.
[Laprie94] J. C. Laprie, editor. Dependability: ba-
sic concepts and terminology. Springer Verlag for
IFIP WG 10.4, 1994.
[Loeckx/Sieber87] Jacques Loeckx and Kurt
Sieber. The Foundations of Program Verification
(Second edition). John Wiley and Sons, New
York, N.Y., 1987.
[Mueller-Olm96] M. Müller-Olm. Modular Com-
piler Verification: A Refinement-Algebraic Ap-
proach Advocating Stepwise Abstraction, volume
1283 of Lecture Notes in Computer Science. Sprin-
ger-Verlag, Berlin, Heidelberg, New York, 1997.
[Moore88] J S. Moore. Piton: A verified assembly
level language. Techn. Report 22, Comp. Logic
Inc, Austin, Texas, 1988.
[Moore96] J S. Moore. Piton: A Mechanically Veri-
fied Assembly-Level Language. Kluwer Academic
Press, Dordrecht, The Netherlands, 1996.
[Mueller-Olm/Wolf00] M. Müller-Olm and
A. Wolf. On the Translation of Procedures to Fi-
nite Machines. In G. Smolka, editor, Programming
Languages and Systems. Proceedings of ESOP
2000, volume 1782 of LNCS, pages 290—304, Ber-
lin, March 2000.
[McCarthy/Painter67] J. McCarthy and J. A. Pain-
ter. Correctness of a compiler for arithmetical ex-
pressions. In J.T. Schwartz, editor, Proceedings of
a Symposium in Applied Mathematics, 19, Mathe-
matical Aspects of Computer Science. American
Mathematical Society, 1967.
[Milne/Strachey76] R. Milne and Ch. Strachey.
A Theory of Programming Language Semantics.
Chapman and Hall, 1976.
[Nielson/Nielson92] H. R. Nielson and F. Nielson.
Semantics with Applications: A Formal Introduction.
John Wiley & Sons, Chichester, 1992.
[Owre+92] S. Owre, J. M. Rushby, and N. Shan-
kar. PVS: A Prototype Verification System. In
Deepak Kapur, editor, Proceedings 11th Interna-
tional Conference on Automated Deduction CADE,
volume 607 of Lecture Notes in Artificial Intelli-
gence, pages 748—752, Saratoga, NY, October
1992. Springer-Verlag.
[Partsch90] H. Partsch. Specification and Trans-
formation of Programs. Texts and Monographs in
Computer Science. Springer-Verlag, 1990.
[Pelegri/Graham88] Eduardo Pelegri-Llopart and
Susan L. Graham. Optimal code generation for
expression trees: An application of {BURS} the-
ory. In ACM-SIGPLAN ACM-SIGACT, editor,
Conference Record of the 15th Annual ACM Sym-
posium on Principels of Programming Languages
(POPL '88), pages 294—308, San Diego, CA, USA,
January 1988. ACM Press.
[Plotkin81] G. D. Plotkin. A structural approach
to operational semantics. Technical Report DAIMI
FN-19, Computer Science Department, Aarhus
University, Aarhus, Denmark, September 1981.
[Pofahl95] E. Pofahl. Methods Used for Inspecting
Safety Relevant Software. In W. J. Cullyer, W. A.
Halang and B. J. Krämer (eds.): High Integrity
Programmable Electronic Systems, Dagstuhl-Sem.-
Rep. 107, p 13,1995.
[Polak81] W. Polak. Compiler specification and
verification. In J. Hartmanis G. Goos, editor, Lec-
Теоретические и методологические основы программирования
30
ture Notes in Computer Science, number 124 in
LNCS. Springer-Verlag, 1981.
[Sampaio93] A. Sampaio. An Algebraic Approach
to Compiler Design. PhD thesis, Oxford University
Computing Laboratory, Programming Research
Group, October 1993. Technical Monograph PRG-
110, Oxford University.
[Scott70] D. S. Scott. Outline of a Mathematical
Theory of Computation. In Proceedings of the 4th
Annual Princeton Conference on Information Sci-
ences and Systems, pages 169—176, Princeton,
1970.
[Spivey92] J. M. Spivey. The Z Notation. Prentice-
Hall International Series in Computer Science.
Prentice Hall, 1992.
[Scott/Strachey71] D. Scott and Ch. Strachey.
Toward a mathematical semantics for computer
languages, pages 19—46. April 1971.
[Stoy77] J.E. Stoy. Denotational Semantics: The
Scott-Strachey Approach to Programming Lan-
guage Theory. MIT Press, Cambridge, MA., Lon-
don, 1977.
[Schweizer/Voss96] G. Schweizer and M. Voss.
Systems engineering and infrastructures for open
computer based systems. Lecture Notes in Com-
puter Science, 1030:317—??, 1996.
[Thompson84] K. Thompson. Reflections on
Trusting Trust. Communications of the ACM,
27(8):761—763, 1984. Also in ACM Turing Award
Lectures: The First Twenty Years 1965—1985, ACM
Press, 1987, and in Computers Under Attack: In-
truders, Worms, and Viruses, ACM Press, 1990.
[Wirth77} N. Wirth. Compilerbau, eine Einführung.
B.G. Teubner, Stuttgart, 1977.
[Wolf00] A. Wolf. Weakest Relative Precondition
Semantics - Balancing Approved Theory and Real-
istic Translation Verification. PhD thesis, Techni-
sche Fakultät der Christian-Albrechts-Universität,
Report No. 2013, Kiel, February 2001.
[ZSI89] ZSI – Zentralstelle für Sicherheit in der
Informationstechnik.IT-Sicherheitskriterien. Bun-
desanzeiger Verlagsgesellschaft, Köln, 1989.
[ZSI90] ZSI – Zentralstelle für Sicherheit in der
Informationstechnik. IT-Evaluationshandbuch.
Bundesanzeiger Verlagsgesellschaft, Köln, 1990.
Date received: 9.11.2002
About authors
Prof. Dr. Wolfgang Goerigk
Professor of Institute of Informatics and
Applied Mathematics
Prof. Dr. Hans Langmaack
Professor of Institute of Informatics and
Applied Mathematics
Місце роботи авторів
Institut für Informatik und Praktische Mathematik
Christian-Albrechts-Universität zu Kiel, Kiel,
Germany
Email: wg@informatik.uni-kiel.de,
hl@informatik.uni-kiel.de
|