Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

Mar 5, 2012

C++: Dynamic linking library code (linux)

This technique is useful for creating a plug-in architecture; create a header with a standard interfaces and functions that third-party developers can then overwrite. Your code will then load the shared library, create pointer references to the standard functions within the library and then execute the third-party code. I will probably write up another post that will display how this works :D

This was created using Code::Blocks; I dunno why, but I find this IDE easier to use than Eclipse or NetBeans for hobby coding.

First, lets create that header file that describes the standard interfaces and functions.

vo.h
// Ensure the programmer doesn't import our declarations twice.
// This also stops name conflicts from occurring early on.
#ifndef VO_H
#define VO_H

// Prevent the c++ compiler from corrupting names
// and creating "unresolved symbols" when linking
#ifdef __cplusplus
extern "C" {
#endif

// Standard initiliaser
int init( void );

#ifdef __cplusplus
}
#endif

#endif
Just to help us visualise what is happening, let's create the implementation of our header. Nothing too complex... all we will do is return the internal state of a global variable (yes this is not good practice, but it's just for show).

vo.cpp

// Import local libraries
#include "voNameGen.h"

// use the std namespace as the default
using namespace std;

bool bInit = false;

int init( void )
{
return bInit;
}
Now we can compile our shared library. Code::Blocks allowed me to create a project with settings to automatically do this for me, but for those using something different this is the command to run (make sure you do so inside the directory that stores the source code!!):

g++ -fPIC -shared vo.cpp -o libVo.so

So now we have our shared library object. Let's have a quick look inside with nm. This tool shows the symbols inside our library, which are used by other programs to 'hook' into our code. After running the command, you will notice our function, init, is at the bottom of the list. This is the 'hook' we are going to use...

nm -d libVo.so

Now let's use our library!!

testrig.c

// Libraries for input and output
#include <stdio.h>
#include <iostream>

// Library for dynamic linking
#include <dlfcn.h>

// Make sure this points to our
// standard header file!!!!
#include "vo.h"

// Use the standard namespace
// Change only if you know what
// you are doing!!
using namespace std;

int main()
{
    // This will hold our reference
    // to our library...
    void *lib_handle;

   // This is our prototype function
   // for init... note the asterixes
   // (Learn about pointers before
   // changing!!!)
   int* (*init)();

   // Hold out error code
   char *error;

   // Using iostream to create output
   cout << "Hello world!" << endl;

   // Opening up our shared library
   lib_handle = dlopen("libVo.so", RTLD_LAZY);

   // If the library failed to open, exit
   if (!lib_handle)
   {
      // This uses stdlib to create output
      fprintf(stderr, "%s\n", dlerror());
      return 1;
   }

   // Point our function to the address of our desired
   // function located in the library....
   init = (int* (*)())dlsym(lib_handle, "init");

   // If we failed to find the function, exit
   if ((error = dlerror()) != NULL)
   {
      // This uses stdlib to create output
      fprintf(stderr, "%s\n", error);
      return 1;
   }

   // Execute the function in the library
   // and pipe the output directly to the
   // command line
   cout << fn() << endl;

   // Close our library and save memory
   dlclose(lib_handle);

   // Exit the program
   return 0;
}
There is nothing more I can really add to this; just go through the code and read the comments! To compile this code manually just type in (the -ldl flag is important as it tells the compiler to use the dlfcn library):

g++ -ldl main.cpp -o main

UPDATE: It has been noticed in the comments that "g++ main.cpp -ldl -o main" works instead of "g++ -ldl main.cpp -o main". Keep this in mind in case you come across any errors.

Now just make sure libVo.so is in the same directory as main before you execute it!

References

A Stack Overflow discussion on the topic
The YoLinux tutorial on the topic of libraries

Feb 28, 2012

C/C++ Tricks

These are some tricks I learned and implemented during my time at UTS (especially in Embedded Software and DADS). These should work in both C and C++, although it largely depends on your compiler/IDE implementation...

Structs and Unions

  • Union: Access a memory location with different variables
  • Struct: A data structure that can be accessed with '.' (ie struct.variable)
The union below creates an int that has its MSB and LSB easily accessible i.e. variable.b.lo will access the least significant bits of variable.i because it shares memory space

NOTE: writing to one union variable will change the value of ALL variables in the union!!!

typedef union BYTES
{
    unsigned int i;
    struct
    {
       unsigned char lo;
       unsigned char hi;
    } b;
} bytes;


Enumerated Data Types


Enums basically convert strings into their machine equivalent. In the BOOLEAN example below FALSE will be set to a value of 0 and TRUE to 1. The more values you put their index will increase by 1.

enum BOOLEAN
{
    FALSE,
    TRUE
};


Defines

The following define is an in-line function that will delay our PIC by a specific number of microseconds. It will basically rewrite any instances of a keyword to whatever we want, including functions or constants.
#define Common_DelayUs(x) { unsigned char _dcnt; \
_dcnt = (x)*((20000000)/(12000000)); \
while(--_dcnt != 0) \
continue; }


Resources

A good resource on C++ data structures
http://www.cplusplus.com/doc/tutorial/other_data_types/

A resource I use most frequently is Peter McLeans lab resources for Embedded Systems. This guy knows his stuff.
http://services.eng.uts.edu.au/pmcl/embsw/index.htm