• No results found

Encoded Base Operations

4. Encoding an Instruction Set

4.2. Encoded Operations

4.2.1. Encoded Base Operations

This section describes the hand-encoded base operations that we provide for the following operations:

• addition, • subtraction, • multiplication,

• signed and unsigned division,

• signed and unsigned comparisons, and

• the boolean logical operations and, or, and xor.

Before describing the hand-encoded base operations, we introduce the basic requirements that encoded operations must fulfill and which we, thus, have to consider during hand-encoding the base operations. Furthermore, for encoding some of the base operations we need to be able to encode if-statements. Hence, we will introduce these also before finally describing the specification of the encoded base operations and their implementation.

Note further that our descriptions in the following consider only the ANB-encoded versions. The AN-encoded version can be obtained by removing instructions that correct signatures. For the ANBD-encoded variant, the version D has to be considered additionally which is handled similar to the signatures. We implemented all three encodings. However, we use only the AN- and ANB- encoded operations in our encoding approaches.

Requirements Posed on Encoded Base Operations

The following requirements that we pose on encoded operations ensure that the code is implemented in a safe way, i. e., without reducing the error detection capabilities of the code implemented.

First of all, it has to be ensured that during an encoded operation the processed No decoding data is not decoded completely or partially because this would open a window

of vulnerability where undetectable errors could happen. Complete decoding happens when a code word is divided by A. If the signature is removed without adequate substitution, this is a partial decoding. In this case the encoding is reduced to an AN-code that, for example, cannot detect the exchange of operands.

The term atomicity originates from the database domain. If a transaction is Atomicity atomic, it is either executed completely or not at all. In the context of encoding,

48 CHAPTER 4. ENCODING AN INSTRUCTION SET

we use atomicity in the sense that an encoded base operation is either executed completely or that we are at least able to notice if parts of an encoded operation were not executed. Thus, we require that an incomplete execution of an encoded operation produces results that are invalid code words. Thereby, we ensure the detection of control flow errors that disturb the execution of an encoded operation.

Each encoded operation has to result in a unique signature, that is, no two Unique signature

encoded operations produce the same output signature when presented with the same input signatures. This ensures detection of operator errors. Otherwise, two operators that produce the same signature for the same input signatures could be exchanged unnoticeably.

Encoding of If-statements

When hand-encoding arithmetic and comparison operations, we need to encode if-statements, for example, to ensure overflow behavior that conforms to the ANSI C-standard. Thus, we explain the encoding of an if-statement with the help of an example whose unencoded version is:

1 i f ( x >= 0 ) {

2 y = z + x ;

3 } e l s e {

4 y = x − y ;

5 }

We have to encode this if-statement in a way that facilitates detection of errors • in the computations executed in the if- and the else-branch,

• in the computation of the condition (x>=0), and

• in the branch itself, i. e., if the taken branch does not match the result of the condition evaluation.

Forin in [For89] presented the following encoded version of the if-statement that fulfills these requirements. The comments show the variable contents for the error-free case: 1 s i g C o n d = sigGEZ ( xc ) ; // i f ( x<0) s i g C o n d = s i g N e g 2 // e l s e s i g C o n d = s i g P o s 3 i f ( xc >= 0 ) { 4 yc = z c+xc ; // yc=A∗ ( z+x)+Bz+Bx 5 } e l s e {

6 yc = xc−yc ; // yc=A∗ ( x−y)+Bx−By

7 yc += ( Bz+Bx ) ; // yc=A∗ ( x−y)+Bx−By+Bz+Bx

8 yc += −(Bx−By ) ; // yc=A∗ ( x−y)+Bz+Bx

9 yc += −s i g N e g+s i g P o s ;

10 // yc=A∗ ( x−y)+Bz+Bx−s i g N e g+s i g P o s

11 }

12 yc += s i g C o n d ; // By=Bz+Bx+s i g P o s

sigGEZ(xc) computes the signature for the greater-equal-comparison of x with zero. It evaluates to two different values: one value if the functional value x represented by xcis greater than or equal to zero (sigPos) and a different value

4.2. ENCODED OPERATIONS 49

We define that after executing the if-statement the signature of yc (the variable

modified by the if-statement) has to be Bz+ Bx+ sigP os, independently of the

chosen branch. The signature of yccould be defined differently. Important is

that after the execution of the if-statement yc can only have that signature if

everything was correctly executed and that any of the described errors would lead to yc having a different signature.

With our intended signature for variables modified by the if-statement, compu- tations of any variable in the else-branch must be completed with:

• the addition of the signature that is generated for this variable in the if-branch,

• the subtraction of the signature that is generated for this variable in the else-branch, and

• the subtraction of the expected value for sigCond for the else-branch (sigNeg) and addition of the one we defined the result to have (sigPos). Note that in the Vital Coded Processor (see Chapter 6) and Compiler Encoded Processing (see Chapter 8) all the values applied to yc in the lines 7 to 9 are

constants that are known at encoding time. Thus, they are precomputed and applied with one addition. This is important because it prevents partial decoding that might happen otherwise if signatures are removed for example in line 8. Furthermore, this ensures that either all of these correction or none are applied. However, if all these corrections are missing, the result produced (yc in our

example) will not be a valid code word.

While computations such as addition, subtraction, and also condition computa- tion are protected as usual by a predetermined signature, the branching behavior is explicitly checked by assuming a specific value for sigCond in the different branches. The addition of the actual sigCond in line 12 implements the check if the correct branch was taken and ensures that the signature of the condition is part of yc’s signature. The latter checks the correctness of the computation of

the condition.

If any of the computations (in the branches or of the condition) or any of the used operands was erroneous, the signature of yc will be destroyed because yc’s

signature depends on any of these computations. If a branch is chosen which does not match x’s size, that is, the expected comparison result, this would also result in a wrong signature of yc, because the addition of sigCond in line 12

would not match the value expected for sigCond in the branches.

Forin [For89] presented the following approach for realizing sigGEZ: Signed numbers are represented using the two’s complement as is done in most systems. When a negative value neg and a positive value pos are encoded using signed operations and the same signature B, the two encoded values negc= A ∗ neg + B

and posc= A ∗ pos + B will not have the same signature if they are interpreted

as unsigned values: (posc mod A) = B 6= (negc mod A) = ((2m+ B) mod A).

Remember m is the width of the binary representation of encoded values. Thus, sigGEZ is defined as follows for xc= A ∗ x + Bx:

50 CHAPTER 4. ENCODING AN INSTRUCTION SET

sigGEZ(xc) =



Bx if x ≥ 0

(2m+ Bx) mod A if x < 0

For more information about encoded comparison operations see page 66.

Specification of Encoded Arithmetic Operations

Before finally discussing our hand-encoded base operations, we have to determine their intended semantics. Arithmetic operations implemented by processors are quite different from mathematical arithmetic using infinite integers. In processors the size of integers is restricted by the chosen data type. If the data type is n bits wide, the computations implemented by a processor take place in the congruence classes modulo 2n: Z/2nZ. If, for example, the addition of two values a and b would result in a value greater than 2n− 1, the addition’s result is (a + b) mod 2n, that is, the addition of a and b is overflown, i. e., wrapped around.

Also higher level programming languages implement this wrapping around. For example, the ANSI C99 standard [ISO99] that defines the programming language C requires this wrapping around in the case of an over- or underflow for unsigned integer types. Note that signed operations require correct modulo arithmetic anyway, that is, the processor operations must wrap around correctly for over- and underflowing computations to implement signed arithmetic. For example, the addition of a negative and a positive number, if interpreted as unsigned values, is nothing else than an overflow that wrapped around correctly. Remember that the implementations of addition, subtraction, and multiplication are equal for signed and unsigned values. They differ only in which flags the processor sets to indicate which over- or underflows happened.

The encoding solutions presented by Forin in [For89] do not consider over- or underflows. Instead the programmer has to ensure that these will not occur. If an overflow happens, it might either lead to invalid code words or to valid code words that contain wrong functional values. The outcome depends on the choice of A. How arithmetic with signed values that requires correct overflows can be encoded is not discussed at all by Forin.

However, we want to execute arbitrary programs without restricting the pro- grammer. Thus, we have to ensure that all operations work as the programmer expects them to work. Hence, it is required that the functional values repre- sented by the encoded values are overflowing and underflowing as they would do without encoding. Table 4.1 summarizes the conditions that we have to fulfill for the different arithmetic operations that are subject to over- or underflows. In the following section, we will show that computations with encoded values require additional corrective actions to be taken to ensure the correct overflow behavior in the domain of the functional values. The reason is that the algebraic structures of unencoded and encoded numbers are not isomorphic. If the two structures of encoded and unencoded numbers shall be isomorphic, A would have to be equal to 2m−n. However, choosing A to be a power of two would result in

4.2. ENCODED OPERATIONS 51

operation requires justification

OF UF

add (signed) × addition of numbers with different signs

add (unsigned) × according to ANSI C99 standard

sub (signed) × subtraction of numbers with different signs

sub (unsigned) × according to ANSI C99 standard

mult (signed) × multiplication of numbers with different signs

mult (unsigned) × according to ANSI C99 standard

Table 4.1.: Requirements on operations with respect to correct realization of overflows (OF) and underflows (UF).

a minimal Hamming distance of only one between valid code words – rendering the code useless against a wide variety of bitflips. Since encoded and functional values are non-isomorphic, encoded numbers normally will not overflow where the functional values do. This means that we have to check for each operation if there would have been an underflow or overflow within the functional values. If so, we have to correct the obtained encoded result accordingly.

Signature Precomputation and Correction

For all the encoded operations, restrictions with respect to the signatures of the input parameters have to be fulfilled. For example, for a division xy, the signature By should be unequal to zero because otherwise the result’s signature Bx

By would be undefined because a division by zero would occur in that case. Furthermore, we ensure that the signature of the result is greater than zero and smaller than A.

Together with our encoded base operations, we provide a signature correction Signature correc- tion functions function for each encoded operation. These facilitate choosing the signatures of

the input parameters appropriately at encoding time or adapting the signatures of encoded values at runtime. Of course, the first method is the preferred one because it induces no runtime costs. Signature correction functions take a randomly chosen signature for each parameter of an operation as input, and provide an adaptation value for each signature. This adaptation value is to be added to the original signature. Thereby, this signature is changed to an appropriate signature for the operation. The described adaptation can also be applied to encoded values at runtime to change the signature of these values. The correction functions are implemented in a way that they try to ensure that the randomness of the given signatures is reduced as few as possible. However, it cannot be completely prevented that the restrictions imposed lead to some signatures being more probable than others. For example, for the naive encoded addition where the result’s signature is the sum of the signatures of the parameters, the input signatures chosen tend to be values smaller than A2. Future implementations of the encoded operations could avoid this issue by correcting signatures for the results instead for the parameters.

52 CHAPTER 4. ENCODING AN INSTRUCTION SET

Furthermore, we provide a signature precomputation function for each encoded Signature precom-

putation functions operation. Given the signatures of the input values, this function computes the expected signature of the return value. Signature correction functions are used, for example, by the encoding compiler presented in Chapter 8 for determining the signatures of intermediate results at encoding time.

In the following, for the sake of simplicity we do not present signature correction and signature precomputation functions. All pseudocode examples presented contain comments at the return statement containing the formula for computing the signature expected for the result produced. The signature precomputation function of an operation just implements this formula. The signatures of the input values are chosen in a way that ensures that the result’s signature is greater than zero and smaller than A.

Addition

Figure 4.3 demonstrates the addition of two unsigned encoded values: xc =

A ∗ x + Bx and yc = A ∗ y + By. In the chosen example, the addition of Overflow

the two functional values x and y overflows in the domain of the functional values. Thus, the result of the addition of the functional values is x + y − 2n because an addition (modulo the domain size 2n) overflows at most once. The expected result of the addition of the encoded values, thus, should be sumexp=

A ∗ (x + y − 2n) + Bx+ By. Instead the result of the addition of the encoded

values xcand ycis sum = A ∗ x + Bx+ A ∗ y + By = A ∗ (x + y) + Bx+ By. The

reason is that the domain of encoded values is large enough that the sum of the encoded values does not overflow. That is due to the choice of A and the data type used.

Even if we choose A in a way that ensures that the domain of the encoded values overflows when the functional values do2, the result would be unequal to

sumexp. The reason is that the overflow of the encoded values corresponds to

modulo 2m on the the encoded value instead of modulo 2n on the functional value. These two different overflows would be equivalent for A = 2m−n. However, as explained before A should not be a power of two due to safety reasons. Thus, both variants of an overflow in an addition of two functional values – with and without overflow in the encoded values – require additional (but different) corrective actions.

Note that sumexp and sum are both multiples of A and carry the expected

signature Bx+ By, that is, both are valid code words. We call sum an incorrect

valid code word because it contains a valid code word with an incorrect functional value. To obtain the correct code word a correction by OVERFLOW CORRECTION = sum − sumexp = A ∗ 2n is required.

2

Appendix A details the requirements for choosing an A that ensures that overflows happen for unencoded functional values and for encoded values at the same places. In that case, if an operation overflows in its execution with functional values, it will also overflow in its execution with encoded values.

4.2. ENCODED OPERATIONS 53 000 000 111 111 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 1111111111111111111111111111111111111111 1111111111111111111111111111111111111111 1111111111111111111111111111111111111111 multiplication with A and addition of signature positive negative positive negative typecast without sign extension negative positive

gray areas depict valid code words

mapping of specific values between different encodings

expected result: obtained result:

OVERFLOW_CORRECTION sumexp= A ∗ (x + y − 2n) + Bx+ By x y A ∗ y + By A ∗ x + Bx = A ∗ 2n 2n− 1 2m− 1 2m− 1 x + y − 2n 0 sum = A ∗ (x + y) + Bx+ By

Figure 4.3.: Demonstration of the effects of encoding on the overflow behavior of an overflowing addition x + y using unsigned encoded values.

The incorrect valid code word sum contains an incorrect functional value in the m-bit domain of the encoded values. If we divide sum by A and do not cast its type back to the n-bit-sized type of the functional values, we obtain x + y instead of x + y − 2n. The latter one can be obtained by casting to the n-bit-sized type of the functional values which is nothing else than a modulo computation with 2n. Hence, incorrect valid code words can be decoded and

their code can be checked successfully.

Thus, a legitimate question is, why we should correct these incorrect valid code Why correct incorrect valid code words? words? Using such results that should have been overflown is no problem in

additions, subtractions, and multiplications. The reason is that these operations and the modulo-2n operation (that is, the cast to the n-bit-sized type) during decoding are commutative. However, this is not the case for divisions and comparisons. These are not commutative with the modulo operation. This will lead to different results for these operations for corrected words, e. g., sumexp,

and uncorrected results, e. g., sum. Furthermore, leaving the values of additions, subtractions, and multiplications uncorrected, could lead to unintended overflows within the encoded values.

Of course, we could just accept the greater domain of encodable numbers and do no corrections, that is, we would not restrict the functional values to values from 0 to 2n− 1. However, realization of arithmetic with signed numbers in the two’s complement requires overflows to wrap around correctly.

The described overflow problem occurs also for signed encoded values. However, Sign overflow the problem does not happen if an addition wraps around 2n, but if an addition

crosses 2n−1, that is, if a so called sign overflow happens. A sign overflow means that one adds two signed positive numbers and the result is too large and flows over into the negative values. Figure 4.4 demonstrates this. Note

54 CHAPTER 4. ENCODING AN INSTRUCTION SET 000 000 111 111 0000000000000000000000000000000 0000000000000000000000000000000 0000000000000000000000000000000 1111111111111111111111111111111 1111111111111111111111111111111 1111111111111111111111111111111 00000000000000000000000000000 00000000000000000000000000000 00000000000000000000000000000 11111111111111111111111111111 11111111111111111111111111111 11111111111111111111111111111 multiplication with A and addition of signature positive positive negative negative positive negative gray areas depict valid code words

mapping of specific values between different encodings sign extension

typecast with

OVERFLOW_CORRECTION obtained result: expected result:

= −2m+ A ∗ 2n 0 2m− 1 2n− 1 x + y y x A ∗ x + Bx A ∗ y + By

sumexp= 2m− A ∗ (2n− (x + y)) + Bx+ By sum = A ∗ (x + y) + Bx+ By

Figure 4.4.: Demonstration of the effects of encoding on the overflow behavior of an overflowing addition x + y using signed encoded values.

that the expected encoded value of x + y in the depicted example is sumexp =

2m− A ∗ (2n− (x + y)) + B

x+ By because of the sign extension made during

encoding. Thus, the required correctional value is OVERFLOW CORRECTION = sum − sumexp = −2m+ A ∗ 2n. This reduces to A ∗ 2n because the overflow

correction is applied modulo 2m.

The pseudocode Listing 4.4 shows our implementation of an encoded addition Implementation

using unsigned encoded values. Note that we denote xy asxˆy in all our pseu-

docode listings. We do not use xˆy for indicating the xor operation that it

signifies in C.

First, the encoded addition adds the unsigned encoded values (line 7) and afterwards it does an encoded overflow correction if required (lines 10 to 24). The overflow correction in Listing 4.4 uses an encoded if-statement to ensure that control flow errors influencing the correction are detectable. Thus, it does not impair the safety that we remove the signatures from result in line 15 because this comparison is checked by the encoding of the if-statement that either applies the overflow correction or not.

Note that in all our pseudocode listings we assume that A is a constant global value that requires at most 31 bits. This ensures that OVERFLOW CORRECTION does not require more than 64 bits for storage.

The implementation of the encoded addition using signed encoded values looks