Archive

Posts Tagged ‘C/C++’

ARM NEON Tutorial in C and Assembler

November 27th, 2011 No comments

The Advanced SIMD extension (aka NEON or “MPE” Media Processing Engine) is a combined 64- and 128-bit single instruction multiple data (SIMD) instruction set that provides standardized acceleration for media and signal processing applications similar to MMX, SSE and 3DNow! extensions found in x86 processors.

Doulos has a video tutorial showing how you can exploit NEON instructions in assembler, how to modify your C code and provides the compile options for gcc to enable NEON during the build.

Abstract:
With the v7-A architecture, ARM has introduced a powerful SIMD implementation called NEON™. NEON is a coprocessor which comes with its own instruction set for vector operations. While NEON instructions could be hand coded in assembler language, ideally we want our compiler to generate them for us. Automatic analysis whether an iterative algorithm can be mapped to parallel vector operations is not trivial not the least because the C language is lacking constructs necessary to support this. This paper explains how the RealView compiler tools (RVCT) and other modern compilers use a blend of sophisticated analysis techniques and language extensions to fulfill their job.

You can download the whiter paper at http://www.doulos.com/knowhow/arm/using_your_c_compiler_to_exploit_neon/Resources/index.php (registration required).

Here’s how to enable NEON instructions (with auto vectorization) for ARM gcc cross-compiler:

arm-none-gnueabi-gcc –mfpu=neon -ftree-vectorize -c sample.c

and armcc compiler:

armcc –cpu=Cortex-A9 -O3 -Otime –vectorize –remarks -c fir_neon.c

I recommand you watch the 17 minutes video tutorial as it explains how to modify your C code to take advantage of NEON instructions with a FIR filter.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter

Development Testing with Static Analysis

November 7th, 2011 1 comment

I’ve recently come across an EE Times article written by Coverity stressing the benefits of static analysis and how it can help finding potential issues in the code early.

They mentioned 3 static analysis techniques:

  • Dataflow analysis
    This technique can find the defect in the listing below during compile time.

    void null_pointer_deref(int x)
    {
        char *p;
        if (x == 0) {
            p = foo();
        } else {
            p = 0;
        }
        if(x != 0) {
            *p;
        } else {
            ...
        }
    }

    If value of x passed into the function is not zero, p is assigned a null pointer with p=0. Then, the next conditional check (x!=0) takes a true branch and in the next line p is dereferenced, leading to a null pointer dereference. This type of issue can be detected at compiled time with dataflow analysis.

  • Interprocedural analysis
    This technique can find defects across function and method boundaries. See listing below:

    void *zero_alloc(size_t size) {
        void *p = malloc(size);
        if (!p) return NULL; 
    
        memset(p,0,size);
        return p;
    }
    
    struct S *create_S(int initial_value) { 
        struct S *s = (struct S *) zero_alloc(sizeof(*s));
        if (!s) return NULL;
        s->field = initial_value;
        return s;
    }
    
    int example_leak(struct S *s, int value) {
        struct S *tmp = s;
        if(!tmp) {
           tmp = create_S(value);
        }
        if(!tmp) return -1;
        ...
        return 0;
    }

    There are 3 functions: example_leak, create_S and zero_alloc. Interprocedural analysis  can go through the code and identify the memory leak.  The analysis engine has to trace the execution to understand that memory is allocated in zero_alloc, initialized in create_S and leaked when variable tmp goes out of scope when we return from function example_leak.

  • False-path pruning
    This technique tries to ensure that the reported defects are real and to do so it analyzes only the executable paths.  Basic static analysis may find defects on paths that can never be executed because of data dependencies as shown in the listing below.

    void null_pointer_deref(int x)
    {
        char *p;
        if (x != 0) {
            p = foo();
        } else {
            p = 0;
        }
        if(x != 0) {
            *p;
        } else {
            ...
        }
    }

    This code is slightly modified from the listing used for dataflow analysis. In this case, dataflow analysis would report a null pointer dereference defect (if x != 0). But that would be a false positive because the execution logic will never traverse this path. False-path analysis technique would prune a path that can never be executed (a false path) and good analysis can report up to 50% fewer false positive.

Those static analysis techniques allows code error discovery earlier and can avoid unnecessary late night debugging. Beside dererenced pointers and memory leak, static analysis can also detect other defects such as memory corruptions caused by incorrect integration operations, misused pointers, other resource leaks besides memory, invalid memory accesses, undefined behavior due to uninitialized value usage and many more.

The rest of the EEtime articles deals with Static Analysis with Agile development and how static analysis can be used on different code branches and shared code, but I’m not going to cover those here.

There are different tools available such as Coverity Static Analysis. See video below for a demo.

There was also a session at Android Open 2011 called Static Analysis For Improved Application Performance And Quality presented by Eric Cloninger (Motorola Mobility). This session showed the types of problems that compilers, debuggers, and test suites can’t solve. Items that often only show up in real-world situations for consumers and end-users and introduces the MOTODEV App Validator tool as a solution for developers. I understand that this tool is free but can only be used for Android applications.

There are also many other tools. Some open source C/C++ static analytic tools include:

Check Wikipedia for a more exhaustive list of commercial and free static analysis tools for different languages.

 

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Categories: Android, Testing, Video Tags: C/C++, coverity, eclipse, llvm

LLVM (Low Level Virtual Machine) Compiler Infrastructure

October 17th, 2011 No comments

Low Level Virtual Machine LogoThe Low Level Virtual Machine (LLVM) is a compiler and toolchain infrastructure, written in C++, designed for compile-time, link-time, run-time, and “idle-time” optimization of programs written in arbitrary programming languages. Originally implemented for C/C++, LLVM is now used with a variety programming languages such as Python, Ruby and may others. Code in the LLVM project is licensed under the “UIUC” BSD-Style license.

LLVM can be used to replace and/or supplement the GNU tools such as gcc, g++, gdb, etc…

LLVM now consists of a number of different sub-projects including:

  1. The LLVM Core libraries provide a source- and target-independent optimizer, along with code generation support for many popular CPUs. These libraries are built around a well specified code representation known as the LLVM intermediate representation (“LLVM IR”). The LLVM Core libraries are well documented, and it is particularly easy to invent your own language (or port an existing compiler) to use LLVM as an optimizer and code generator.
  2. Clang is a “LLVM native” C/C++/Objective-C/C++ compiler, which aims to deliver amazingly fast compiles (e.g. up to 3x faster than GCC when compiling Objective-C code in a debug configuration), extremely useful error and warning messages and to provide a platform for building source level tools such as the Clang Static Analyzer which automatically finds bugs in your code.
  3. dragonegg and llvm-gcc 4.2 integrate the LLVM optimizers and code generator with respectively the GCC 4.5  and GCC 4.2 parsers. This allows LLVM to compile Ada, Fortran, and other languages supported by the GCC compiler frontends, and provides high-fidelity drop-in compatibility with their respective versions of GCC.
  4. The LLDB project builds on libraries provided by LLVM and Clang to provide a native debugger. It uses the Clang ASTs and expression parser, LLVM JIT, LLVM disassembler, etc. It is also faster and much more memory efficient than GDB at loading symbols.
  5. The libc++ and libc++ ABI projects provide a standard compliant and high-performance implementation of the C++ Standard Library, including full support for C++’0x.
  6. The compiler-rt project provides highly tuned implementations of the low-level code generator support routines like “__fixunsdfdi” and other calls generated when a target doesn’t have a short sequence of native instructions to implement a core IR operation.
  7. The vmkit project is an implementation of the Java and .NET Virtual Machines that is built on LLVM technologies.
  8. The klee project implements a “symbolic virtual machine” which uses a theorem prover to try to evaluate all dynamic paths through a program in an effort to find bugs and to prove properties of functions. A major feature of klee is that it can produce a testcase in the event that it detects a bug.
  9. The SAFECode project is a memory safety compiler for C/C++ programs. It instruments code with run-time checks to detect memory safety errors (e.g., buffer overflows) at run-time. It can be used to protect software from security attacks and can also be used as a memory safety error debugging tool like Valgrind.

LLVM is used by several companies and open source projects such as:

  • Adobe: Optimizer and JIT codegen for the Hydra Language and ActionScript 3 Compiler.
  • Apple: LLVM is used to compile MacOS X (OpenCL and OpenGL compilation)
  • Electronic Arts: Experimental backend for custom language implementation
  • Nvidia: OpenCL runtime compiler (Clang + LLVM)
  • PyPy Project: Python interpreter written in Python. Targets LLVM and C.
  • iPhone tool chain: llvm-gcc Compiler for iPhone Dev Wiki toolchain.
  • Mono: Mono Project has an option to use LLVM for JIT compilation

Linaro will also investigate LLVM and decide whether it will support an LLVM toolchain for ARM in the future. This will be decided in November and if they finally go for it, implementation will start later in 2012.

If you want to try it you can either download the source code or a binary for your operating systems or alternatively you can run the online demo that allows you to compile a C or C++ program and generate x86 binaries, LLCM C++ API code or LLVM assembly. If you are using Ubuntu, llvm should already be installed. But if it is not installed on your distribution you can run:

sudo apt-get install llvm clang

clang will generate more explicit and detailled error messages than gcc. For example:

 $ gcc-4.2 -fsyntax-only -Wformat format-strings.c
  format-strings.c:91: warning: too few arguments for format
 $ clang -fsyntax-only format-strings.c
  format-strings.c:91:13: warning: '.*' specified field precision is missing a matching 'int' argument
   printf("%.*d");

Here’s what LLVM C++ API Code looks like for “hello world!” C program (beginning only):

// Generated by llvm2cpp - DO NOT MODIFY!

#include <llvm/LLVMContext.h>
#include <llvm/Module.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Constants.h>
#include <llvm/GlobalVariable.h>
#include <llvm/Function.h>
#include <llvm/CallingConv.h>
#include <llvm/BasicBlock.h>
#include <llvm/Instructions.h>
#include <llvm/InlineAsm.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/MathExtras.h>
#include <llvm/Pass.h>
#include <llvm/PassManager.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Assembly/PrintModulePass.h>
#include <algorithm>
using namespace llvm;

Module* makeLLVMModule();

int main(int argc, char**argv) {
  Module* Mod = makeLLVMModule();
  verifyModule(*Mod, PrintMessageAction);
  PassManager PM;
  PM.add(createPrintModulePass(&outs()));
  PM.run(*Mod);
  return 0;
}

Module* makeLLVMModule() {
 // Module Construction
 Module* mod = new Module("/tmp/webcompile/_23517_0.bc", getGlobalContext());
 mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
 mod->setTargetTriple("x86_64-unknown-linux-gnu");
...

and LLVM Assembly (full code):

; ModuleID = '/tmp/webcompile/_23857_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"

@str = internal constant [12 x i8] c"Hello World\00"

define i32 @main(i32 %argc, i8** nocapture %argv) nounwind {
  %puts = tail call i32 @puts(i8* getelementptr inbounds ([12 x i8]* @str, i64 0, i64 0))
  ret i32 0
}

declare i32 @puts(i8* nocapture) nounwind

Finally, here’s a small benchmark compiling dropbear-0.53.1 with gcc 4.4.3 and clang 1.1 (llvm 2.7):

GCC 4.4.3:

./configure
time make
real 1m17.518s
user 1m5.012s
sys 0m10.789s

Clang 1.1:

make clean
export CC=clang
./configure
time make
real 1m9.178s
user 0m56.668s
sys 0m13.309s

This shows clang is about 10% faster than gcc to build dropbear.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter

Cross Compiling Boost C++ Libraries for ARM

October 3rd, 2011 12 comments

Boost provides free peer-reviewed portable C++ source libraries. Ten Boost libraries are already included in the C++ Standards Committee’s Library Technical Report and will be in the new C++11 Standard.

The Boost C++ libraries are already included in popular Linux and Unix distributions such as Fedora, Debian, Ubuntu and NetBSD and are used by projects such as Python, Xibo, Civilization IV, etc..

Here are the steps to cross-compile Boost C++ libraries for arm using arm-linux-guneabi-g++:

  1. Download the source code:

    wget http://sourceforge.net/projects/boost/files/boost/1.47.0/boost_1_47_0.tar.bz2/download

  2. Extract the source code:

    mv download boost.tar.bz2
    tar xjvf boost.tar.bz2
    cd boost_1_47_0/

  3. Bootstrap the code:

    ./bootstrap.sh

  4. Modify the configuration file (project-build.jam) to use the ARM toolchain by replacing the line with “using gcc” by:

    using gcc : arm : arm-linux-gnueabi-g++ ;

  5. Install the python development package:

    sudo apt-get install python-dev

  6. Build and install the boost libraries:

    ./bjam install toolset=gcc-arm –prefix=~/edev/beagleboard/libs –disable-long-double -sNO_ZLIB=1 -sNO_BZIP2=1

This was tested in Ubuntu 11.04 (natty) and 10.04 LTS with linaro g++ toolchain.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter

Best Practices for Writing Safer C Code

September 13th, 2011 4 comments

Thomas Honold wrote an article published on EETimes giving 17 steps to safer C code. Not only this article provides tips to write safer C code, but I believe those steps are simply best practices when writing C code for embedded systems as they shorten the software life cycle by making it easier for a software team to write, debug and maintain code and by improving the software QA procedure.

Here’s a summary of the 17 steps to achieve safer C code:

  1. Follow the rules you’ve read a hundred times:
    • Initialize variables before use.
    • Do not ignore compiler warnings.
    • Check return values.
  2. Use enums as error types.
    Define an ENUM_MAX value at the end, so that the code to check the range does not have to be modified each time you add a new error code.
  3. Expect to fail
    Always assume there will be an error and set to default return value to error.
  4. Check input values: never trust a stranger
    Check all input values for consistency at the outmost layer of your software architecture.
  5. Write once, read many times
    Write code to make it readable by others. Declare meaningful variable names and add plenty of comments.
  6. When in doubt, leave it out
    If you are not sure you need a specific function in your API do not add it. If somebody uses it and you later decide it’s not necessary to keep this function, it will break his code.
  7. Use the right tools
    Use an IDE or editor that suits your need (e.g. Ultraedit), build tools (e..g GNU Tools), version control system (e.g. svn, git) and possibly a code style checker such as Artistic Style.
  8. Define the software requirements first
    if you don’t define the requirements, you can’t test your final software properly and can not determine if you have finished your project.
  9. During boot phase, dump all available versions
    If you have several chipset (e.g. FPGA) that each run its own firmware, so when you boot make sure you display all available firmware versions to facilitate debugging and (production) testing.
  10. Use a software version string for every release
    Make you update your software version each time you release it for testing or production. If your version is stored in the version control repository commit it. The best is to have software version string generated automatically for each build.
  11. Design for reuse: use standards
    Do not create types that are already defined in the standard libraries.
  12. Expose only what is needed
    Do not declare variable or functions globally, if they do not need to. It may lead to naming conflicts,  make your design non-modular or non-thread safe.
  13. Make sure you’ve used “volatile” correctly
    Use the volatile type for a variable shared by an ISR and any other code,  a global variable accessed by two or more RTOS tasks, a pointer to a memory-mapped peripheral register (or register set) or a delay loop counter.
  14. Don’t start with optimization as the goal
    Focus on flexibility first to make it easier to add new features as they are requested and optimize the code for speed or size later if necessary.
  15. Don’t write complex code
    Do not write code that is too complex for readability or maintenance. It’s quite difficult to assess whether a code is complex or not (it’s also subjective), but there are tools to help such as http://www.scitools.com.
  16. Use a static code checker
    You most probably have code rules. make sure you have to script or tools to check those rules or you can be sure they’ll never be checked.
  17. Myths and sagas
    Discard myths such as “you can’t use dynamic memory allocation”, this can be done safely at initialization phase, even though you might have to be careful with malloc during program execution as it can lead to memory fragmentation.

For code examples and more detailed explanations, please refer to the original EETimes article “Seventeen steps to safer C code

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter

What Programming Language Should I Learn ?

September 12th, 2011 No comments

“What programming language should I  learn ?” is a question often asked by people new to software development.

The answer is always “it depends”. But for embedded systems, it seems C language is a must as you can see in the chart below (Source: “The 2011 Embedded Market Study” by Embedded.com).

What programming should I learn for embedded systems development ?

For the 2011 survey, 1886 respondents from across the embedded industry answered that their embedded project was mostly programmed in C language  (62%), followed by C++ (22%), assembler (5%) and Java (2%). The other languages were all under 1%.

 

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Categories: Programming Tags: C/C++, assembler, java, programming