注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

widebright的个人空间

// 编程和生活

 
 
 

日志

 
 

linux动态链接库导出函数控制  

2009-12-11 20:24:54|  分类: linux相关 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
windows 环境的vc的话,可以方便的指定__declspec(dllexport) 关键字来控制是否把dll中的函数导出。
我也来测试一下linux下面是如何做的:
先看gcc 和ld的相关选项

======================================
gcc 选项
       -shared
           Produce a shared object which can then be linked with other objects
           to form an executable.  Not all systems support this option.  For
           predictable results, you must also specify the same set of options
           that were used to generate code (-fpic, -fPIC, or model suboptions)
           when you specify this option.[1]


       -fpic
           Generate position-independent code (PIC) suitable for use in a
           shared library, if supported for the target machine.  Such code
           accesses all constant addresses through a global offset table
           (GOT).  The dynamic loader resolves the GOT entries when the
           program starts (the dynamic loader is not part of GCC; it is part
           of the operating system).  If the GOT size for the linked
           executable exceeds a machine-specific maximum size, you get an
           error message from the linker indicating that -fpic does not work;
           in that case, recompile with -fPIC instead.  (These maximums are 8k
           on the SPARC and 32k on the m68k and RS/6000.  The 386 has no such
           limit.)

           Position-independent code requires special support, and therefore
           works only on certain machines.  For the 386, GCC supports PIC for
           System V but not for the Sun 386i.  Code generated for the IBM
           RS/6000 is always position-independent.

           When this flag is set, the macros "__pic__" and "__PIC__" are
           defined to 1.

       -fPIC
           If supported for the target machine, emit position-independent
           code, suitable for dynamic linking and avoiding any limit on the
           size of the global offset table.  This option makes a difference on
           the m68k, PowerPC and SPARC.

           Position-independent code requires special support, and therefore
           works only on certain machines.

           When this flag is set, the macros "__pic__" and "__PIC__" are
           defined to 2.

       -rdynamic
           Pass the flag -export-dynamic to the ELF linker, on targets that
           support it. This instructs the linker to add all symbols, not only
           used ones, to the dynamic symbol table. This option is needed for
           some uses of "dlopen" or to allow obtaining backtraces from within
           a program.


      -fvisibility=default|internal|hidden|protected
           Set the default ELF image symbol visibility to the specified
           option---all symbols will be marked with this unless overridden
           within the code.  Using this feature can very substantially improve
           linking and load times of shared object libraries, produce more
           optimized code, provide near-perfect API export and prevent symbol
           clashes.  It is strongly recommended that you use this in any
           shared objects you distribute.

           Despite the nomenclature, "default" always means public ie;
           available to be linked against from outside the shared object.
           "protected" and "internal" are pretty useless in real-world usage
           so the only other commonly used option will be "hidden".  The
           default if -fvisibility isn't specified is "default", i.e., make
           every symbol public---this causes the same behavior as previous
           versions of GCC.

           A good explanation of the benefits offered by ensuring ELF symbols
           have the correct visibility is given by "How To Write Shared
           Libraries" by Ulrich Drepper (which can be found at
           <http://people.redhat.com/~drepper/>)---however a superior solution
           made possible by this option to marking things hidden when the
           default is public is to make the default hidden and mark things
           public.  This is the norm with DLL's on Windows and with
           -fvisibility=hidden and "__attribute__ ((visibility("default")))"
           instead of "__declspec(dllexport)" you get almost identical
           semantics with identical syntax.  This is a great boon to those
           working with cross-platform projects.


           For those adding visibility support to existing code, you may find
           #pragma GCC visibility of use.  This works by you enclosing the
           declarations you wish to set visibility for with (for example)
           #pragma GCC visibility push(hidden) and #pragma GCC visibility pop.
           Bear in mind that symbol visibility should be viewed as part of the
           API interface contract and thus all new code should always specify
           visibility when it is not the default ie; declarations only for use
           within the local DSO should always be marked explicitly as hidden
           as so to avoid PLT indirection overheads---making this abundantly
           clear also aids readability and self-documentation of the code.
           Note that due to ISO C++ specification requirements, operator new
           and operator delete must always be of default visibility.

           Be aware that headers from outside your project, in particular
           system headers and headers from any other library you use, may not
           be expecting to be compiled with visibility other than the default.
           You may need to explicitly say #pragma GCC visibility push(default)
           before including any such headers.

           extern declarations are not affected by -fvisibility, so a lot of
           code can be recompiled with -fvisibility=hidden with no
           modifications.  However, this means that calls to extern functions
           with no explicit visibility will use the PLT, so it is more
           effective to use __attribute ((visibility)) and/or #pragma GCC
           visibility to tell the compiler which extern declarations should be
           treated as hidden.

           Note that -fvisibility does affect C++ vague linkage entities. This
           means that, for instance, an exception class that will be thrown
           between DSOs must be explicitly marked with default visibility so
           that the type_info nodes will be unified between the DSOs.

           An overview of these techniques, their benefits and how to use them
           is at <http://gcc.gnu.org/wiki/Visibility>.

===================================
ld命令选项 


       -E
       --export-dynamic
       --no-export-dynamic
           When creating a dynamically linked executable, using the -E option
           or the --export-dynamic option causes the linker to add all symbols
           to the dynamic symbol table.  The dynamic symbol table is the set
           of symbols which are visible from dynamic objects at run time.

           If you do not use either of these options (or use the
           --no-export-dynamic option to restore the default behavior), the
           dynamic symbol table will normally contain only those symbols which
           are referenced by some dynamic object mentioned in the link.

           If you use "dlopen" to load a dynamic object which needs to refer
           back to the symbols defined by the program, rather than some other
           dynamic object, then you will probably need to use this option when
           linking the program itself.

           You can also use the dynamic list to control what symbols should be
           added to the dynamic symbol table if the output format supports it.
           See the description of --dynamic-list.

           Note that this option is specific to ELF targeted ports.  PE
           targets support a similar function to export all symbols from a DLL
           or EXE; see the description of --export-all-symbols below.


       --dynamic-list=dynamic-list-file
           Specify the name of a dynamic list file to the linker.  This is
           typically used when creating shared libraries to specify a list of
           global symbols whose references shouldn't be bound to the
           definition within the shared library, or creating dynamically
           linked executables to specify a list of symbols which should be
           added to the symbol table in the executable.  This option is only
           meaningful on ELF platforms which support shared libraries.

           The format of the dynamic list is the same as the version node
           without scope and node name.  See VERSION for more information.

       --dynamic-list-data
           Include all global data symbols to the dynamic list.



       --version-script=version-scriptfile
           Specify the name of a version script to the linker.  This is typically used when creating shared libraries to
           specify additional information about the version hierarchy for the library being created.  This option is only
           fully supported on ELF platforms which support shared libraries; see VERSION.  It is partially supported on PE
           platforms, which can use version scripts to filter symbol visibility in auto-export mode: any symbols marked
           local in the version script will not be exported.

     #VERSION 文件格式可以参考这里     http://sourceware.org/binutils/docs-2.20/ld/VERSION.html#VERSION
=========================================
dlopen
The function dlopen() loads the dynamic library file named by the null-terminated string filename and returns an opaque "handle" for the dynamic library. If filename is NULL, then the returned handle is for the main program. If filename contains a slash ("/"), then it is interpreted as a (relative or absolute) pathname. Otherwise, the dynamic linker searches for the library as follows (see ld.so(8) for further details):

o
    (ELF only) If the executable file for the calling program contains a DT_RPATH tag, and does not contain a DT_RUNPATH tag, then the directories listed in the DT_RPATH tag are searched.
o
    If the environment variable LD_LIBRARY_PATH is defined to contain a colon-separated list of directories, then these are searched. (As a security measure this variable is ignored for set-user-ID and set-group-ID programs.)
o
    (ELF only) If the executable file for the calling program contains a DT_RUNPATH tag, then the directories listed in that tag are searched.
o
    The cache file /etc/ld.so.cache (maintained by ldconfig(8)) is checked to see whether it contains an entry for filename.
o
    The directories /lib and /usr/lib are searched (in that order).

If the library has dependencies on other shared libraries, then these are also automatically loaded by the dynamic linker using the same rules. (This process may occur recursively, if those libraries in turn have dependencies, and so on.)

One of the following two values must be included in flag:

RTLD_LAZY
    Perform lazy binding. Only resolve symbols as the code that references them is executed. If the symbol is never referenced, then it is never resolved. (Lazy binding is only performed for function references; references to variables are always immediately bound when the library is loaded.)
RTLD_NOW
    If this value is specified, or the environment variable LD_BIND_NOW is set to a non-empty string, all undefined symbols in the library are resolved before dlopen() returns. If this cannot be done, an error is returned.

Zero of more of the following values may also be ORed in flag:

RTLD_GLOBAL
    The symbols defined by this library will be made available for symbol resolution of subsequently loaded libraries.
RTLD_LOCAL
    This is the converse of RTLD_GLOBAL, and the default if neither flag is specified. Symbols defined in this library are not made available to resolve references in subsequently loaded libraries.
RTLD_NODELETE (since glibc 2.2)
    Do not unload the library during dlclose(). Consequently, the library's static variables are not reinitialised if the library is reloaded with dlopen() at a later time. This flag is not specified in POSIX.1-2001.
RTLD_NOLOAD (since glibc 2.2)
    Don't load the library. This can be used to test if the library is already resident (dlopen() returns NULL if it is not, or the library's handle if it is resident). This flag can also be used to promote the flags on a library that is already loaded. For example, a library that was previously loaded with RTLD_LOCAL can be re-opened with RTLD_NOLOAD | RTLD_GLOBAL. This flag is not specified in POSIX.1-2001.
RTLD_DEEPBIND (since glibc 2.3.4)
    Place the lookup scope of the symbols in this library ahead of the global scope. This means that a self-contained library will use its own symbols in preference to global symbols with the same name contained in libraries that have already been loaded. This flag is not specified in POSIX.1-2001.

If filename is a NULL pointer, then the returned handle is for the main program. When given to dlsym(), this handle causes a search for a symbol in the main program, followed by all shared libraries loaded at program startup, and then all shared libraries loaded by dlopen() with the flag RTLD_GLOBAL.

External references in the library are resolved using the libraries in that library's dependency list and any other libraries previously opened with the RTLD_GLOBAL flag. If the executable was linked with the flag "-rdynamic" (or, synonymously, "--export-dynamic"), then the global symbols in the executable will also be used to resolve references in a dynamically loaded library.

If the same library is loaded again with dlopen(), the same file handle is returned. The dl library maintains reference counts for library handles, so a dynamic library is not deallocated until dlclose() has been called on it as many times as dlopen() has succeeded on it. The _init routine, if present, is only called once. But a subsequent call with RTLD_NOW may force symbol resolution for a library earlier loaded with RTLD_LAZY.

If dlopen() fails for any reason, it returns NULL.
dlsym
The function dlsym() takes a "handle" of a dynamic library returned by dlopen() and the null-terminated symbol name, returning the address where that symbol is loaded into memory. If the symbol is not found, in the specified library or any of the libraries that were automatically loaded by dlopen() when that library was loaded, dlsym() returns NULL. (The search performed by dlsym() is breadth first through the dependency tree of these libraries.) Since the value of the symbol could actually be NULL (so that a NULL return from dlsym() need not indicate an error), the correct way to test for an error is to call dlerror() to clear any old error conditions, then call dlsym(), and then call dlerror() again, saving its return value into a variable, and check whether this saved value is not NULL.

There are two special pseudo-handles, RTLD_DEFAULT and RTLD_NEXT. The former will find the first occurrence of the desired symbol using the default library search order. The latter will find the next occurrence of a function in the search order after the current library. This allows one to provide a wrapper around a function in another shared library.
dlclose
The function dlclose() decrements the reference count on the dynamic library handle handle. If the reference count drops to zero and no other loaded libraries use symbols in it, then the dynamic library is unloaded.

The function dlclose() returns 0 on success, and non-zero on error.
The obsolete symbols _init and _fini
The linker recognizes special symbols _init and _fini. If a dynamic library exports a routine named _init, then that code is executed after the loading, before dlopen() returns. If the dynamic library exports a routine named _fini, then that routine is called just before the library is unloaded. In case you need to avoid linking against the system startup files, this can be done by giving gcc the "-nostartfiles" parameter on the command line.

Using these routines, or the gcc -nostartfiles or -nostdlib options, is not recommended. Their use may result in undesired behavior, since the constructor/destructor routines will not be executed (unless special measures are taken).

Instead, libraries should export routines using the __attribute__((constructor)) and __attribute__((destructor)) function attributes. See the gcc info pages for information on these. Constructor routines are executed before dlopen() returns, and destructor routines are executed before dlclose() returns.


========================================
测试看看:



-----------------------main.c -----------------------------------
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#include<dlfcn.h>

char str[] = "\x8b\x45\x1c\x85\xc0\x75\x23\x83\x3d\xf5\x26\x04\x00\x00\x75\x10\x49\x63\xfd\x49 ";
//  compile it with gcc -g and then do "disassemble str"

int test (int i)
{
 
  printf("i=%d\n" ,i);
}

int main()
{
    int (*test2)(int);
    int (*test3)(int);
    int *handler;
 


    handler=(int*)dlopen("test.so", RTLD_LAZY);
    if (!handler) {
        printf( "加载模块错误 %s\n", dlerror() );
        return;
    }
 
    test3 = dlsym(handler, "test3");
        if (test3) test3(3);

     test2 = dlsym(handler, "test2");
        if (test2) test2(2);
 
        dlclose(handler);

 exit(0);

}

------------------------------------------------------------------
$ gcc -rdynamic main.c -o main -ldl

$ readelf -s main

Symbol table '.dynsym' contains 25 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlclose@GLIBC_2.0 (2)
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (3)
     5: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlsym@GLIBC_2.0 (2)
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlopen@GLIBC_2.1 (4)
     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.0 (3)
     8: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlerror@GLIBC_2.0 (2)
     9: 00000000     0 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.0 (3)
    10: 0804a020     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    11: 0804a028    22 OBJECT  GLOBAL DEFAULT   24 str
    12: 0804a048     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    13: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    14: 0804a020     0 NOTYPE  WEAK   DEFAULT   24 data_start
    15: 080486b0     0 FUNC    GLOBAL DEFAULT   14 _start
    16: 080488f8     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    17: 080488fc     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    18: 08048850    90 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    19: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    20: 08048764    28 FUNC    GLOBAL DEFAULT   14 test   ///test 在这里导出了
    21: 08048780   178 FUNC    GLOBAL DEFAULT   14 main
    22: 080485ec     0 FUNC    GLOBAL DEFAULT   12 _init
    23: 08048840     5 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    24: 080488dc     0 FUNC    GLOBAL DEFAULT   15 _fini

Symbol table '.symtab' contains 79 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048134     0 SECTION LOCAL  DEFAULT    1
     2: 08048148     0 SECTION LOCAL  DEFAULT    2
     3: 08048168     0 SECTION LOCAL  DEFAULT    3
     4: 0804818c     0 SECTION LOCAL  DEFAULT    4
     5: 0804823c     0 SECTION LOCAL  DEFAULT    5
     6: 080482a4     0 SECTION LOCAL  DEFAULT    6
     7: 08048434     0 SECTION LOCAL  DEFAULT    7
     8: 08048520     0 SECTION LOCAL  DEFAULT    8
     9: 08048554     0 SECTION LOCAL  DEFAULT    9
    10: 080485a4     0 SECTION LOCAL  DEFAULT   10
    11: 080485ac     0 SECTION LOCAL  DEFAULT   11
    12: 080485ec     0 SECTION LOCAL  DEFAULT   12
    13: 0804861c     0 SECTION LOCAL  DEFAULT   13
    14: 080486b0     0 SECTION LOCAL  DEFAULT   14
    15: 080488dc     0 SECTION LOCAL  DEFAULT   15
    16: 080488f8     0 SECTION LOCAL  DEFAULT   16
    17: 08048934     0 SECTION LOCAL  DEFAULT   17
    18: 08049f04     0 SECTION LOCAL  DEFAULT   18
    19: 08049f0c     0 SECTION LOCAL  DEFAULT   19
    20: 08049f14     0 SECTION LOCAL  DEFAULT   20
    21: 08049f18     0 SECTION LOCAL  DEFAULT   21
    22: 08049ff0     0 SECTION LOCAL  DEFAULT   22
    23: 08049ff4     0 SECTION LOCAL  DEFAULT   23
    24: 0804a020     0 SECTION LOCAL  DEFAULT   24
    25: 0804a040     0 SECTION LOCAL  DEFAULT   25
    26: 00000000     0 SECTION LOCAL  DEFAULT   26
    27: 00000000     0 SECTION LOCAL  DEFAULT   27
    28: 00000000     0 SECTION LOCAL  DEFAULT   28
    29: 00000000     0 SECTION LOCAL  DEFAULT   29
    30: 00000000     0 SECTION LOCAL  DEFAULT   30
    31: 00000000     0 SECTION LOCAL  DEFAULT   31
    32: 00000000     0 SECTION LOCAL  DEFAULT   32
    33: 00000000     0 FILE    LOCAL  DEFAULT  ABS init.c
    34: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    35: 08049f04     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_LIST__
    36: 08049f0c     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_LIST__
    37: 08049f14     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    38: 080486e0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
    39: 0804a040     1 OBJECT  LOCAL  DEFAULT   25 completed.6990
    40: 0804a044     4 OBJECT  LOCAL  DEFAULT   25 dtor_idx.6992
    41: 08048740     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
    42: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    43: 08049f08     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_END__
    44: 08048934     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    45: 08049f14     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    46: 080488b0     0 FUNC    LOCAL  DEFAULT   14 __do_global_ctors_aux
    47: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
    48: 08049ff4     0 OBJECT  LOCAL  HIDDEN   23 _GLOBAL_OFFSET_TABLE_
    49: 0804a024     0 OBJECT  LOCAL  HIDDEN   24 __dso_handle
    50: 08049f10     0 OBJECT  LOCAL  HIDDEN   19 __DTOR_END__
    51: 08049f04     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_end
    52: 08049f04     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_start
    53: 080488aa     0 FUNC    LOCAL  HIDDEN   14 __i686.get_pc_thunk.bx
    54: 08049f18     0 OBJECT  LOCAL  HIDDEN   21 _DYNAMIC
    55: 0804a020     0 NOTYPE  WEAK   DEFAULT   24 data_start
    56: 08048840     5 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    57: 080486b0     0 FUNC    GLOBAL DEFAULT   14 _start
    58: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    59: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    60: 080488f8     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    61: 080488dc     0 FUNC    GLOBAL DEFAULT   15 _fini
    62: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlclose@@GLIBC_2.0
    63: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    64: 080488fc     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    65: 0804a020     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    66: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlsym@@GLIBC_2.0
    67: 0804a028    22 OBJECT  GLOBAL DEFAULT   24 str
    68: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlopen@@GLIBC_2.1
    69: 08048850    90 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    70: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.0
    71: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    72: 08048764    28 FUNC    GLOBAL DEFAULT   14 test
    73: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlerror@@GLIBC_2.0
    74: 0804a048     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    75: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    76: 00000000     0 FUNC    GLOBAL DEFAULT  UND exit@@GLIBC_2.0
    77: 08048780   178 FUNC    GLOBAL DEFAULT   14 main
    78: 080485ec     0 FUNC    GLOBAL DEFAULT   12 _init


----------------------------------------------------------------------------------

$ gcc main.c -o main -ldl
$ readelf -s main

Symbol table '.dynsym' contains 11 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlclose@GLIBC_2.0 (2)
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (3)
     5: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlsym@GLIBC_2.0 (2)
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlopen@GLIBC_2.1 (4)
     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.0 (3)
     8: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlerror@GLIBC_2.0 (2)  ///没有把 test函数导出
     9: 00000000     0 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.0 (3)
    10: 080486fc     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used

Symbol table '.symtab' contains 79 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048134     0 SECTION LOCAL  DEFAULT    1
     2: 08048148     0 SECTION LOCAL  DEFAULT    2
     3: 08048168     0 SECTION LOCAL  DEFAULT    3
     4: 0804818c     0 SECTION LOCAL  DEFAULT    4
     5: 080481cc     0 SECTION LOCAL  DEFAULT    5
     6: 080481ec     0 SECTION LOCAL  DEFAULT    6
     7: 0804829c     0 SECTION LOCAL  DEFAULT    7
     8: 08048334     0 SECTION LOCAL  DEFAULT    8
     9: 0804834c     0 SECTION LOCAL  DEFAULT    9
    10: 0804839c     0 SECTION LOCAL  DEFAULT   10
    11: 080483a4     0 SECTION LOCAL  DEFAULT   11
    12: 080483e4     0 SECTION LOCAL  DEFAULT   12
    13: 08048414     0 SECTION LOCAL  DEFAULT   13
    14: 080484b0     0 SECTION LOCAL  DEFAULT   14
    15: 080486dc     0 SECTION LOCAL  DEFAULT   15
    16: 080486f8     0 SECTION LOCAL  DEFAULT   16
    17: 08048734     0 SECTION LOCAL  DEFAULT   17
    18: 08049f04     0 SECTION LOCAL  DEFAULT   18
    19: 08049f0c     0 SECTION LOCAL  DEFAULT   19
    20: 08049f14     0 SECTION LOCAL  DEFAULT   20
    21: 08049f18     0 SECTION LOCAL  DEFAULT   21
    22: 08049ff0     0 SECTION LOCAL  DEFAULT   22
    23: 08049ff4     0 SECTION LOCAL  DEFAULT   23
    24: 0804a020     0 SECTION LOCAL  DEFAULT   24
    25: 0804a040     0 SECTION LOCAL  DEFAULT   25
    26: 00000000     0 SECTION LOCAL  DEFAULT   26
    27: 00000000     0 SECTION LOCAL  DEFAULT   27
    28: 00000000     0 SECTION LOCAL  DEFAULT   28
    29: 00000000     0 SECTION LOCAL  DEFAULT   29
    30: 00000000     0 SECTION LOCAL  DEFAULT   30
    31: 00000000     0 SECTION LOCAL  DEFAULT   31
    32: 00000000     0 SECTION LOCAL  DEFAULT   32
    33: 00000000     0 FILE    LOCAL  DEFAULT  ABS init.c
    34: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    35: 08049f04     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_LIST__
    36: 08049f0c     0 OBJECT  LOCAL  DEFAULT   19 __DTOR_LIST__
    37: 08049f14     0 OBJECT  LOCAL  DEFAULT   20 __JCR_LIST__
    38: 080484e0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
    39: 0804a040     1 OBJECT  LOCAL  DEFAULT   25 completed.6990
    40: 0804a044     4 OBJECT  LOCAL  DEFAULT   25 dtor_idx.6992
    41: 08048540     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
    42: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    43: 08049f08     0 OBJECT  LOCAL  DEFAULT   18 __CTOR_END__
    44: 08048734     0 OBJECT  LOCAL  DEFAULT   17 __FRAME_END__
    45: 08049f14     0 OBJECT  LOCAL  DEFAULT   20 __JCR_END__
    46: 080486b0     0 FUNC    LOCAL  DEFAULT   14 __do_global_ctors_aux
    47: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
    48: 08049ff4     0 OBJECT  LOCAL  HIDDEN   23 _GLOBAL_OFFSET_TABLE_
    49: 08049f04     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_end
    50: 08049f04     0 NOTYPE  LOCAL  HIDDEN   18 __init_array_start
    51: 08049f18     0 OBJECT  LOCAL  HIDDEN   21 _DYNAMIC
    52: 0804a020     0 NOTYPE  WEAK   DEFAULT   24 data_start
    53: 08048640     5 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    54: 080484b0     0 FUNC    GLOBAL DEFAULT   14 _start
    55: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    56: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    57: 080486f8     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    58: 080486dc     0 FUNC    GLOBAL DEFAULT   15 _fini
    59: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlclose@@GLIBC_2.0
    60: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    61: 080486fc     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    62: 0804a020     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    63: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlsym@@GLIBC_2.0
    64: 0804a028    22 OBJECT  GLOBAL DEFAULT   24 str
    65: 0804a024     0 OBJECT  GLOBAL HIDDEN   24 __dso_handle
    66: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlopen@@GLIBC_2.1
    67: 08049f10     0 OBJECT  GLOBAL HIDDEN   19 __DTOR_END__
    68: 08048650    90 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    69: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.0
    70: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    71: 08048564    28 FUNC    GLOBAL DEFAULT   14 test
    72: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlerror@@GLIBC_2.0
    73: 0804a048     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    74: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    75: 00000000     0 FUNC    GLOBAL DEFAULT  UND exit@@GLIBC_2.0
    76: 080486aa     0 FUNC    GLOBAL HIDDEN   14 __i686.get_pc_thunk.bx
    77: 08048580   178 FUNC    GLOBAL DEFAULT   14 main
    78: 080483e4     0 FUNC    GLOBAL DEFAULT   12 _init



====================================================================
$ gcc -rdynamic -fPIC  main.c -o main -ldl

$ readelf  -s main

Symbol table '.dynsym' contains 25 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlclose@GLIBC_2.0 (2)
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (3)
     5: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlsym@GLIBC_2.0 (2)
     6: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlopen@GLIBC_2.1 (4)
     7: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.0 (3)
     8: 00000000     0 FUNC    GLOBAL DEFAULT  UND dlerror@GLIBC_2.0 (2)
     9: 00000000     0 FUNC    GLOBAL DEFAULT  UND exit@GLIBC_2.0 (3)
    10: 0804a020     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    11: 0804a028    22 OBJECT  GLOBAL DEFAULT   24 str
    12: 0804a048     0 NOTYPE  GLOBAL DEFAULT  ABS _end
    13: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
    14: 0804a020     0 NOTYPE  WEAK   DEFAULT   24 data_start
    15: 080486b0     0 FUNC    GLOBAL DEFAULT   14 _start
    16: 08048918     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    17: 0804891c     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    18: 08048870    90 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    19: 0804a040     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    20: 08048764    45 FUNC    GLOBAL DEFAULT   14 test
    21: 08048791   201 FUNC    GLOBAL DEFAULT   14 main
    22: 080485ec     0 FUNC    GLOBAL DEFAULT   12 _init
    23: 08048860     5 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    24: 080488fc     0 FUNC    GLOBAL DEFAULT   15 _fini

Symbol table '.symtab' contains 79 entries:

=======================================================================









------test.c---------------------
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 

extern int test (int i);

int test2 (int i)
{
     test(i);
     printf("this is test2\n");
}

int test3 (int i)
{
     printf("this is test 3\n");
}
-----------------------------------------------

$ gcc -shared -fPIC test.c -o test.so


$ readelf -s test.so

Symbol table '.dynsym' contains 14 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND test
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     5: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.1.3 (3)
     6: 00002014    22 OBJECT  GLOBAL DEFAULT   22 str
     7: 00002034     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     8: 0000202c     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     9: 000004ec    49 FUNC    GLOBAL DEFAULT   12 test2  /////////////////////
    10: 0000202c     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    11: 000003a8     0 FUNC    GLOBAL DEFAULT   10 _init
    12: 00000588     0 FUNC    GLOBAL DEFAULT   13 _fini
    13: 0000051d    38 FUNC    GLOBAL DEFAULT   12 test3   ////////////////////

Symbol table '.symtab' contains 57 entries:

====================================================================

$ ./main
加载模块错误 test.so: cannot open shared object file: No such file or directory  

找不到 test.so文件,他不会自动在当前目录下搜索啊。
那就设置好这个LD_LIBRARY_PATH这个环境变量吧,我是不想复制到系统目录去了

$ echo $LD_LIBRARY_PATH

$ export LD_LIBRARY_PATH=`pwd`
$ echo $LD_LIBRARY_PATH
/home/widebright/桌面/测试用例


--------------------------
gcc -rdynamic -fPIC  main.c -o main -ldl
gcc -shared -fPIC test.c -o test.so
使用上面编译选线,结果
$ ./main
this is test 3
i=2
this is test2
--------------------------------
gcc -fPIC  main.c -o main -ldl
gcc -shared -fPIC test.c -o test.so
使用上面编译选线,结果test.so就找不到 main中export出来的test函数了
$ ./main
this is test 3
./main: symbol lookup error: /home/widebright/桌面/测试用例/test.so: undefined symbol: test
--------------------------------
gcc -rdynamic main.c -o main -ldl
gcc -shared -fPIC test.c -o test.so
使用上面编译选线,结果还是可以执行,说明 -fPIC对程序来说好像用处不大。
$ ./main
this is test 3
i=2
this is test2
------------------------------------------------
gcc -rdynamic main.c -o main -ldl
gcc -shared  test.c -o test.so
使用上面编译选线,也还能正确运行 -fPIC 有什么作用啊,不明显
$ ./main
this is test 3
i=2
this is test2
---------------------------------------------




----visibility.txt------------------
{
    global:
            test3;  
    local: *;
};
-------------------

gcc -rdynamic main.c -o main -ldl
gcc -shared  test.c -o test.so -Wl,--version-script=visibility.txt

$ gcc -shared  test.c -o test.so -Wl,--version-script=visibility.txt
$ ./main
this is test 3

可以看到 使用--version-script=visibility.txt 参数控制之后,只有test3才被导出了

readelf -s test.so

Symbol table '.dynsym' contains 7 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND test
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     5: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.1.3 (3)
     6: 0000041b    20 FUNC    GLOBAL DEFAULT   12 test3    //visibility.txt文件里面指定了 test3才导出了, test2不再导出了

======================================



gcc -shared  test.c -o test.so  -fvisibility=hidden

----当 -fvisibility=hidden 设置为hidden之后,所有的都函数不再导出了。
readelf -s test.so

Symbol table '.dynsym' contains 11 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND test    ///这个还是会在这里,知道是外部函数来的
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     5: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.1.3 (3)
     6: 0000202c     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     7: 00002024     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     8: 00002024     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
     9: 0000035c     0 FUNC    GLOBAL DEFAULT   10 _init
    10: 000004e8     0 FUNC    GLOBAL DEFAULT   13 _fini

==============================================

我们给要导出到函数加上 属性控制,改成这样,
----------test.c-----------------
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
 

extern int test (int i);

 __attribute ((visibility)) int test2 (int i)
{
     test(i);
     printf("this is test2\n");
}

 __attribute ((visibility)) int test3 (int i)
{
     printf("this is test 3\n");
}

-------------------------------

$ gcc -shared  test.c -o test.so  -fvisibility=hidden
$ readelf -s test.so

Symbol table '.dynsym' contains 13 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     3: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND test
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     5: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.1.3 (3)
     6: 0000202c     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     7: 00002024     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     8: 000004bc    31 FUNC    GLOBAL DEFAULT   12 test2    //这次就会导出了
     9: 00002024     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    10: 000003a0     0 FUNC    GLOBAL DEFAULT   10 _init
    11: 00000528     0 FUNC    GLOBAL DEFAULT   13 _fini
    12: 000004db    20 FUNC    GLOBAL DEFAULT   12 test3


$ ./main
this is test 3
i=2
this is test2
-----------------------------------------------------






总结:

通过gcc命令的-fvisibility=hidden 选项和  "__attribute__ ((visibility("default")))" 语法扩展 可以得到 vc中
__declspec(dllexport)"的效果。

采用ld的  --version-script=version-scriptfile 参数 类似vc中到  *.DEF 文件,也可以用来统一链接库到输出与否。


测完才发现,gcc帮助文档提到的 “How To Write Shared Libraries” 这篇文章上面解释的更完整一些,
一个pdf文档,在google搜索一下就可以找到了。

其他的办法还包括:
1. static 定义函数

2、libtool的-export-symbols参数
$ libtool --mode=link gcc -o libfoo.la \
  foo.lo -export-symbols=foo.sym

3.使用alias属性来隐藏具体的函数名
int next (void) {   
  return ++last_int;        
}                          
extern __typeof (next) next_int
                                      
  __attribute ((alias ("next"),
                                        
                visibility ("hidden")));


  评论这张
 
阅读(775)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017