分类
dpdk analysis

dlsym参数 RTLD_NEXT详解

最近在看dpdk的代码,看到examples/performance-thread/pthread_shim/pthread_shim.c文件 有一段宏

static void *__libc_dl_handle = RTLD_NEXT;
#define get_addr_of_loaded_symbol(name) do {                            \
        char *error_str;                                                \
        _sys_pthread_funcs.f_##name = dlsym(__libc_dl_handle, (#name)); \
        error_str = dlerror();                                          \
        if (error_str != NULL) {                                        \
                fprintf(stderr, "%s\n", error_str);                     \
        }                                                               \
} while (0)

宏里面 dlsym函数的用法让我觉得好奇怪,之前没见过。于是用man 查看了手册 RTLD_NEXT Find the next occurrence of the desired symbol in the search order after the current object. This allows one to provide a wrapper around a function in another shared object, so that, for example, the definition of a function in a preloaded shared object (see LD_PRELOAD in ld.so(8)) can find and invoke the “real” function provided in another shared object (or for that matter, the “next” definition of the function in cases where there are multiple lay‐ ers of preloading). 大概意思就是说,传入这个参数,找到的函数指针是后面第一次出现这个函数名的函数指针。理解上有点模糊,我写了几行代码加深理解。 文件 first_one.c

#include <stdio.h>
void print_message()
{
    printf("the first lib~~\n");
}
void first()
{
    printf("init first\n");
}

编译成动态库

gcc -fpic -c first_one.c
gcc --share first_one.o -o libfirst_one.so

文件 second_one.c

#include <stdio.h>
void print_message()
{
    printf("the second lib~~\n");
}

void second()
{
    printf("init second \n");
}

编译成动态库

gcc -fpic -c second_one.c
gcc --share second_one.o -o libsecond_one.so

文件 wrap.c

# define RTLD_NEXT      ((void *) -1l)
#include <stdio.h>
#include <dlfcn.h>
#include <errno.h>
void(*f)();
void load_func() __attribute__((constructor));
void load_func()
{
    f = (void(*)())dlsym(RTLD_NEXT,"print_message");
    char *error_str;
    error_str = dlerror();
    if (error_str != NULL) {
        printf("%s\n", error_str);
    }
    printf("load func first f=%p\n",f);

}
void print_message()
{
    printf("the wrap lib~~\n");
    f();
}

编译成动态库

gcc -fpic -c wrap.c
gcc --share wrap.o -o libwrap.so

文件 main.c

void print_message();
void first();
void second();
int main()
{
    first();
    second();
    print_message();
    return 0;
}

编译成 目标文件

gcc -c main.c

第一种方式生成链接文件

gcc -o first main.o  -lwrap -lfirst_one  -lsecond_one -ldl -L.

第二种方式生成连接文件

gcc -o second main.o  -lwrap -lsecond_one -lfirst_one  -ldl -L.

设置执行时环境变量

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.

查看库加载顺序

duanxc@DESKTOP-LVGREDM:~/dlysm$ ldd first
    linux-vdso.so.1 =>  (0x00007fffee2e9000)
    libwrap.so (0x00007f586c1a0000)
    libfirst_one.so (0x00007f586bf90000)
    libsecond_one.so (0x00007f586bd80000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f586bb70000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f586b7a0000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f586c400000)

duanxc@DESKTOP-LVGREDM:~/dlysm$ ldd second
    linux-vdso.so.1 =>  (0x00007fffc2321000)
    libwrap.so (0x00007fddd1d40000)
    libsecond_one.so (0x00007fddd1b30000)
    libfirst_one.so (0x00007fddd1910000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fddd1700000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fddd1330000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fddd2000000)

查看执行结果

duanxc@DESKTOP-LVGREDM:~/dlysm$ ./first
load func first f=0x7f600f3e06c0
init first
init second
the wrap lib~~
the first lib~~

duanxc@DESKTOP-LVGREDM:~/dlysm$ ./second
load func first f=0x7f92457e06c0
init first
init second
the wrap lib~~
the second lib~~

分析 库libfirst_one.so 和库libsecond_one.so中都有print_message函数,根据库的加载顺序,出入RTLD_NEXT作为句柄的dlsym函数会返回对应的函数指针,当libfirst_one.so先加载则返回这个库中的函数地址,反之则返回libsecond_on.so中的函数指针。 如上例,我们可以通过这个特性对libc中的库函数进行封装,用于测试目的。如wrap.c中所写,先获取libc中想要封装的函数名称的指针,然后在wrap.c中写对应函数名实现。在实现时,先做一些记录或者统计,然后再通过指针调用libc中的函数。当程序开发完毕,不需要记录或统计值时,在连接时,不连接wrap库即可。

分类
WordPress WordPress插件开发

WordPress插件开发 – 第1章 关于插件开发

欢迎来到WordPress插件开发系列。不关你是第一次写插件还是已经写了很多插件了,我们都希望这篇教程能够帮助你写出更棒的插件。

这个教程包括以下一系列主题:需要包含在插件头部的所有东西,如何让插件更安全,以及介绍一些可以帮助你开发插件的工具。同时这也是一个完善的过程,如果你找到哪些部分的功能是缺失的或者是不完整的,你可以修改完善这部分内容。

WordPress有以下三个主要的元素:

  • 内核
  • 主题
  • 插件

这篇教程是介绍插件以及插件是怎样在WordPress里面工作的。

1.1    为什么需要开发插件

WordPress里面最重要的一条规则就是:不要去修改WordPress的内核。也就是说,你不能通过去修改WordPress的内核相关的文件来添加你需要的功能。这样规定的原因是,每当WordPress更新的时候,所有的内核文件都会被覆盖。所以,如果你想在你的网站中添加自己的新功能的话,一定要使用插件。

WordPress的插件可以很简单也可以很复杂,完全根据你的需求决定。最简单的插件可以就是一个单独的PHP文件。“Hello Dolly”就是一个这种简单插件的例子。这样的插件只需要提供一个“插件头”,一系列的PHP功能函数,以及一些绑定你的函数的“钩子”。

插件允许你在不触碰WordPress内核的前提下最大限度地扩展WordPress的功能。

1.2    什么是插件

插件其实就是扩展WordPress核心功能的扩展包。WordPress插件主要由PHP代码以及一些附加资源组成,比如图像,css和JavaScript。

扩展WordPress的方式就是创建你自己的插件,这可以实现比如在WordPress已经提供的功能的基础上再添加新的功能。例如,你可以写一个插件,这个插件的功能是显示前十篇最近发表的文章。

或者,可以使用插件来自定义文章类型,你可以通过创建插件来创建一个完整的订票系统,包括支持邮件提醒,自定义票的状态以及面向客户的接口。可以说只有你想不到,没有你做不到。

大部分WordPress插件由许多文件组成,但是插件中真正需要的只是一个在头部指定了特定格式头部的主文件。

比如我们介绍的第一个插件“Hello Dolly”,仅仅由82行代码组成。Hello Doly的功能是显示WordPress管理员中最流行歌曲的歌词。当然,还需要一些css文件来正确布局歌词的显示格式。

作为一个插件开发者,你有一个很大的机会来创建一个会受到万人追捧的插件。你需要做的仅仅是把你的想法变成代码。这就是这篇教程要做的事情。

分类
未分类

Hello world!

printf("Hello world!\n");