Tuesday, February 22, 2011

In Linux, how to export function symbols?

the global visibility you can set in the compiler flags by (the symbols are public by default.):
-fvisibility=default
or
-fvisibility=hidden

and then the equivalents attributes are:
__attribute__ ((visibility("default"))) // (similar to __declspec(dllexport))
or
__attribute__ ((visibility("hidden")))

How to make and manage shared objects in GNU/Linux environment

Introduction
For scalability, evolutivity and debug purposes, it is interesting to make applications be based on add-ons. The shared object concept which comes along with the GNU/Linux environment can achieve it.

There are two ways to load and link with shared objects :

* Implicitly by gathering the shared objects in some directories and make the system load and link them automatically at program startup;
* Explicitly by making the program load and link the shared objects thanks to some library services (i.e. libdl.so).


In both ways, there are some tricks and traps to know to make sure everything goes well. For example, thanks to this link, we realized that we must use "g++ (or gcc) -shared" instead of "ld -shared" to make the shared libraries.

For the following examples, we use a main program which source file is base.cc or base1.cc and a shared object which source file is base_shared.cc.

We chose very simple C++ written examples instead of C written programs because this is the most general case (C is a subset of C++) and the situation where most of the problems can appear when linking and loading shared objects.

The shared object defines a global C++ class which must be initialized at library loading time and deinitialized at library unloading time. This kind of initialization/deinitialization routines are called static constructors/destructors. Moreover, the shared object offers an entry point (base_initialize()) in C language (to avoid mangling problems) which is called by the main program.


1. Implicit loading/linking of shared objects
The implicit linking consists to start a main program referencing symbols located in some shared objects which are automatically loaded and linked to the main program at startup.

1.1. TEST 1 : Building of shared lib with "ld"
--> Location of the shared libs at program startup :
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`

--> Make the shared library :

g++ -c base_shared.cc
ld -shared base_shared.o -o libbase_shared.so

--> Make the main program

g++ base.cc -L`pwd` -lbase_shared
/usr/bin/ld: a.out : hidden symbole « __dso_handle » in /usr/lib/gcc/i486-linux-gnu/4.1.2/crtbegin.o est référencé par DSO
/usr/bin/ld: édition de lien finale en échec: Section non-représentable pour la sortie
collect2: ld returned 1 exit status
We can see that the linking of the main program fails because of the referencing of a hidden symbol : __dso_handle.

1.2. TEST 2 : Building of shared lib with "gcc"
--> Location of the shared libs at program startup :
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`

--> Make the shared library :

g++ -c base_shared.cc
g++ -shared base_shared.o -o libbase_shared.so

--> Make the main program

g++ base.cc -L`pwd` -lbase_shared

--> Run the program

./a.out
Constructor of toto
Main entry point
Shared lib entry point, toto's var = 18
Destructor of toto


We can see that the program is dynamically linked to the shared object. The static constructor and destructor of the shared library are run automatically at loading/unloading time.

2. Explicit loading/linking of shared objects
The explicit linking consists to start a main program referencing symbols located in some shared objects which are loaded and linked to the main program through a call to "dlopen()".

2.1. TEST 1 : Building of shared lib with "ld"
--> Make the shared library :
g++ -c base_shared.cc
ld -shared base_shared.o -o libbase_shared.so

--> Make the main program

g++ base1.cc -ldl

--> Run the program

> ./a.out
Main entry point
./libbase_shared.so: undefined symbol: __dso_handle
We can see that the loading of the shared object fails because of an unresolved symbol : __dso_handle.

2.2. TEST 2 : Building of shared lib with "gcc"

--> Make the shared library :
g++ -c base_shared.cc
g++ -shared base_shared.o -o libbase_shared.so

--> Make the main program

g++ base1.cc -l dl

--> Run the program

> ./a.out
Main entry point
Loading shared lib...
Constructor of toto
Shared lib entry point, toto's var = 18
Destructor of toto

We can see that the static constructor and destructor of the shared library are run automatically at loading/unloading time (i.e. During the call to "dlopen()").

Conclusion
Which ever the way we load and link the shared objects (implicitly or explicitly), it appears that the best way to make shared objects is to use "g++ -shared" and not "ld -shared". This makes the shared object prepared to run the static constructors at loading time and the static destructors at unloading time.


Resources

* Howto shared libraries

About the author
The author is an engineer in computer sciences located in France. He can be contacted here or you can have a look at his WEB home page.

base.cc
#include 


extern "C" { void base_initialize(void); }


int main(void)
{

printf("Main entry point\n");

// Call a function in shared lib
base_initialize();

return 0;
} // main

base1.cc
#include 
#include 

extern "C" { void base_initialize(void); }


int main(void)
{
void *hdl;
void *sym;
char *err;
void (*call)(void);

printf("Main entry point\n");

// Check parameters
printf("Loading shared lib...\n");
hdl = dlopen("./libbase_shared.so", RTLD_LAZY | RTLD_GLOBAL);
if (NULL == hdl)
{
  fprintf(stderr, "%s\n", dlerror());
  return 1;
}

// Clear any pending error message
(void)dlerror();

// Look for symbol in the shared lib
sym = dlsym(hdl, "base_initialize");
if (NULL == sym)
{
  err = dlerror();
  if (err)
  {
    fprintf(stderr, "%s\n", err);
    return 1;
  }
  else
  {
    // The symbol has been found but it is NULL
    fprintf(stderr, "The symbol is NULL\n");
    return 1;
  }
}

// Call a function in shared lib
call = (void (*)(void))sym;
(*call)();

return 0;
} // main

base_shared.cc
#include 
#include 


using namespace std;



class toto
{
public:
toto() { cout << "Constructor of toto\n"; var = 18; };
~toto() { cout << "Destructor of toto\n"; var = 0; }
int var;
};


toto glob_class;


extern "C"
{

void base_initialize(void)
{

printf("Shared lib entry point, toto's var = %d\n", glob_class.var);

}

}
Compiler's version
gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu5)

Monday, February 14, 2011

GCC编译提示显示乱码

WindowsXP下使用SecureCRT SSH到Linux服务器上使用 gcc 编译程序发现里面带乱码,且多到几乎看不清意思的程度。
原来我们的Linux服务器是中文环境,于是改为英文环境,设置方法如下:
系统语言设置:

[root@localhost pro2]# vi /etc/sysconfig/i18n
LANG="en_US.UTF-8"

现在问题好多了,不过还没有完全解决。如果编译错误,gcc的输出信息中也有少量乱码,
在网上搜索了好久都没有找到有效的解决办法,在一高人的提示下,搞定了。跟大家分享下:
解决办法,在用户的配置的文件中加入下面的一句话:
export LANG=C
或者直接在编译命令行中输入export lang=c,但重新打开窗口又要设置

how to make a jar file that include dll files

(Ref: http://stackoverflow.com/questions/1611357/how-to-make-a-jar-file-that-include-dll-files)
Just package it anywhere in the jar. One thing you have to keep in mind though - before you can use the DLLs you need to actually extract these from the JAR and dump these on the hard disk somewhere otherwise you won't be able to load these

So basically - I did JNI project for the client where I will use such jar packaged within the war. However - before running any native methods I would get the DLL as a resource and write it to the disc into temp directory. Then I would run regular initialization code where my DLL is set to the same location I just wrote DLL to

Oh, and just in case: there's nothing special about packaging dll or any other file into jar. It's just like packaging stuff into zip

Here's some code I just digged out
public class Foo {
private static final String LIB_BIN = "/lib-bin/";
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private final static String ACWRAPPER = "acwrapper";
private final static String AAMAPI = "aamapi51";
private final static String LIBEAU = "libeay32";

static {
        logger.info("Loading DLL");
        try {
                System.loadLibrary(ACWRAPPER);
                logger.info("DLL is loaded from memory");
        } catch (UnsatisfiedLinkError e) {
                loadFromJar();
        }
}

/**
 * When packaged into JAR extracts DLLs, places these into
 */
private static void loadFromJar() {
        // we need to put both DLLs to temp dir
        String path = "AC_" + new Date().getTime();
        loadLib(path, ACWRAPPER);
        loadLib(path, AAMAPI);
        loadLib(path, LIBEAU);
}

/**
 * Puts library to temp dir and loads to memory
 */
private static void loadLib(String path, String name) {
        name = name + ".dll";
        try {
                // have to use a stream
                InputStream in = ACWrapper.class.getResourceAsStream(LIB_BIN + name);
                // always write to different location
                File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
                logger.info("Writing dll to: " + fileOut.getAbsolutePath());
                OutputStream out = FileUtils.openOutputStream(fileOut);
                IOUtils.copy(in, out);
                in.close();
                out.close();
                System.load(fileOut.toString());
        } catch (Exception e) {
                throw new ACCoreException("Failed to load required DLL", e);
        }
}
    // blah-blah - more stuff
}


A word of caution on this approach - be sure you clean up the temp files. If you re-use the same path each time, consider what happens if multiple applications use your JAR (one will fail if the other already has a lock on the temp file). Just be careful - sometimes it's easier to deploy the JAR and DLLs separately. – Kevin Day Oct 24 '09 at 5:50

Code can be changed to overwrite previously installed file. In my case - this was a web app which will not be frequently recycled, bu indeed - if you just copy the code "as is" you will get new copy of DLLs each time you execute it – DroidIn.net Oct 24 '09 at 6:03

One thing to keep in mind: I was using JNI DLLs that were dependent on other DLLs. I included all DLLs inside a jar and used the code above to unpack. But I was getting java.lang.UnsatisfiedLinkError exceptions saying "Can't find dependent libraries". The problem is that you must call System.load() on the DLLs in order such that dependent DLLs are loaded first. – Liron Yahdav May 24 '10 at 21:27

C和C++混编,c调用C++,c++调用C

这两天一直在解决这样的一个问题,项目之中有如下的需求:
嵌入式的产品,算法部分用C++实现,而控制程序和其它程序用C实现.
这就要求可以通过C来调用C++的算法程序.
同时,这个项目有一个PC的demo程序,是用VC开发的,这又要求C++能调用C的主控程序.
一直知道应该用extern,但是具体该如何使用,一直也不是很清楚.
首先给出百度来的一些相关的理论:
摘抄一:
1.引言
  C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变 量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”), 因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明 显的不同。

2.从标准头文件说起
  某企业曾经给出如下的一道面试题:
  面试题
  为什么标准头文件都有类似以下的结构?
#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */
  分析
  显然,头文件中的编译宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止该头文件被重复引用。
  那么
#ifdef __cplusplus
extern "C" {
 #endif
 #ifdef __cplusplus
}
#endif 
的作用又是什么呢?我们将在下文一一道来。
  3.深层揭密extern "C"
  extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。
  被extern "C"限定的函数或变量是extern类型的;
  extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:
  extern int a;
  仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。
   通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数 时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编 译生成的目标代码中找到此函数。
  与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
  被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;
  未加extern “C”声明时的编译方式
  首先看看C++中对类似C的函数是怎样编译的。
  作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。
   _foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。
  同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。
  未加extern "C"声明时的连接方式
  假设在C++中,模块A的头文件如下:
// 模块A头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
在模块B中引用该函数:
// 模块B实现文件 moduleB.cpp
#include "moduleA.h"
foo(2,3);
实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!
  加extern "C"声明后的编译和连接方式
  加extern "C"声明后,模块A的头文件变为:
// 模块A头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
extern "C" int foo( int x, int y );
#endif
在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:
  (1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;
  (2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。
  如果在模块A中函数声明了foo为extern "C"类型,而模块B中包含的是extern int foo( int x, int y ) ,则模块B找不到模块A中的函数;反之亦然。
   所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这个语言是怎么 做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理解许多问题):
  实现C++与C及其它语言的混合编程。
  明白了C++中extern "C"的设立动机,我们下面来具体分析extern "C"通常的使用技巧。
  4.extern "C"的惯用法
  (1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:
extern "C"
{
#include "cExample.h"
}
而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。
  笔者编写的C++引用C函数例子工程中包含的三个文件的源代码如下:
/* c语言头文件:cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);
#endif
/* c语言实现文件:cExample.c */
#include "cExample.h"
int add( int x, int y )
{
 return x + y;
}
// c++实现文件,调用add:cppFile.cpp
extern "C"
{
 #include "cExample.h"
}
int main(int argc, char* argv[])
{
 add(2,3);
 return 0;
}
如果C++调用一个C语言编写的.DLL时,当包括.DLL的头文件或声明接口函数时,应加extern "C" { }。
  (2)在C中引用C++语言中的函数和变量时,C++的头文件需添加extern "C",但是在C语言中不能直接引用声明了extern "C"的该头文件,应该仅将C文件中将C++中定义的extern "C"函数声明为extern类型。
  笔者编写的C引用C++函数例子工程中包含的三个文件的源代码如下:
//C++头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
//C++实现文件 cppExample.cpp
#include "cppExample.h"
int add( int x, int y )
{
 return x + y;
}
/* C实现文件 cFile.c
/* 这样会编译出错:#include "cExample.h" */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
 add( 2, 3 );
 return 0;
}
摘抄二:
http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html
下面是我的代码和具体的分析:
首先,定义了一个cpp的文件,完全是函数的形式,所以关于类的使用,已经先封装掉.(这是因为,如果有类的话,C调用起来要复杂很多):
C++的
头文件相关部分如下:
#ifdef   __cplusplus  
extern "C" {
#endif
     float go(int object,int detail);
//在这个extern体里面,可以包含多个需要开放给C的函数
#ifdef   __cplusplus  
}
#endif
而头文件的函数的具体实现当然是在cpp中了.
然后,调用该Cpp的C的头文件如下:
/*注意,一定不能#include 前面的那个C++文件的头文件,否则会编译出错,因为要用C编译器去编译C++的文件,肯定出错.*/
#ifdef __cplusplus //这些语句是为了将C的goC函数开放给C++的文件调用的.
extern "C" {
#endif
Float goC(int object,int detail);
extern FP32 go (object,detail);  //这句话是对应C++里面的extern出来的函数体
#ifdef __cplusplus
}
#endif

//然后,调用该C的实现文件中,有类似如下的内容:
Float goC(int object,int detail)
{
     return go(object,detail);   //实现调用,一定要有extern才能这么用,否则会不能有正确的返回值
}

//最后,在需要调用C的函数的C++文件中,应该这么用:
#include C的头文件
需要哪个函数直接用就好了.

Monday, February 7, 2011

Windows XP Embedded

http://www.winbile.net/cms/news/Newsc7c36i694.aspx

http://bbs.mid123.com/thread-540-1-1.html

http://blog.csdn.net/techyang/archive/2008/09/08/2898483.aspx

DDos

http://qnatech.wordpress.com/2008/11/25/how-to-prevent-dos-denial-of-service-attack/