21.03.2013 Views

Problem - Kevin Tafuro

Problem - Kevin Tafuro

Problem - Kevin Tafuro

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

ANSI/ISO 9899-1990 standard, which includes any modern C compiler. The key is<br />

the use of the volatile keyword, which essentially instructs the compiler not to optimize<br />

out expressions that involve the variable because there may be side effects<br />

unknown to the compiler. A commonly cited example of this is a variable that may<br />

be modified by hardware, such as a real-time clock.<br />

It’s proper to declare any variable containing sensitive information as volatile.<br />

Unfortunately, many programmers are unaware of what this keyword means, so it is<br />

frequently omitted. In addition, simply declaring a variable as volatile may not be<br />

enough. Whether or not it is enough often depends on how aggressive a particular<br />

compiler is in performing dead-code elimination. Early implementations of deadcode<br />

elimination optimizations were probably far less aggressive than current ones,<br />

and logically you can safely assume that they will perhaps get more aggressive in the<br />

future. It is best to protect code from any current optimizing compiler, as well as any<br />

that may be used in the future.<br />

If simply declaring a variable as volatile may not be enough, what more must be<br />

done? The answer is to replace calls to functions like memcpy( ), memmove( ), and<br />

memset( ) with handwritten versions. These versions may perform less well, but they<br />

will ensure their expected behavior. The solution we have provided above does just<br />

that. Notice the use of the volatile keyword on each function’s argument list. An<br />

important difference between these functions and typical implementations is the use<br />

of that keyword. When memset( ) is called, the volatile qualifier on the buffer passed<br />

into it is lost. Further, many compilers have built-in implementations of these functions<br />

so that the compiler may perform heavier optimizing because it knows exactly<br />

what the functions do.<br />

Here is code that implements three different methods of writing data to a buffer that<br />

a compiler may try to optimize away. The first is spc_memset( ), which acts just like<br />

the standard memset( ) function, except that it guarantees the write will not be optimized<br />

away if the destination is never used. Then we implement spc_memcpy( ) and<br />

spc_memmove( ), which are also analogs of the appropriate standard library functions.<br />

#include <br />

volatile void *spc_memset(volatile void *dst, int c, size_t len) {<br />

volatile char *buf;<br />

for (buf = (volatile char *)dst; len; buf[--len] = c);<br />

return dst;<br />

}<br />

volatile void *spc_memcpy(volatile void *dst, volatile void *src, size_t len) {<br />

volatile char *cdst, *csrc;<br />

cdst = (volatile char *)dst;<br />

csrc = (volatile char *)src;<br />

while (len--) cdst[len] = csrc[len];<br />

706 | Chapter 13: Other Topics<br />

This is the Title of the Book, eMatter Edition<br />

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!