减少程序的sleep()函数

时间:2012-02-15 22:40:19

标签: linux sleep

我有一个为Linux开发的二进制程序,它从服务器的网络流中读取行。它的通信加密的方式需要我很长时间才能搞清楚,所以我无法重写它。

输出每一行后,程序调用{​​{1}}(我发现这是使用nanosleep(100000000))但是,当服务器快速连续发送多行时,实际流和输出之间有很大的延迟

由于我没有程序的源代码,我的问题是:有没有办法减少这个软件的睡眠时间? “加速”它?

作为参考,该计划是Punkbuster的PBUcon

2 个答案:

答案 0 :(得分:4)

您可以尝试LD_PRELOAD技巧:

/* nosleep.c */
#include <time.h>
#include <unistd.h>

int sleep(unsigned int seconds)
{
    return 0;
}
int usleep(useconds_t usec)
{
    return 0;
}
int nanosleep(const struct timespec *req, struct timespec *rem)
{
    return 0;
}

然后编译:

$ gcc -o libnosleep.so -shared nosleep.c -fpic

然后运行您的程序:

$ LD_PRELOAD=./libnosleep.so pbucon

您应该注意以下几点:

  1. 它将取代nanosleep的每次调用,而不仅仅是您不喜欢的调用,并且可能会产生微妙的不良影响。如果您认为需要,可以检查参数的特定值。
  2. 它不适用于suid / sgid程序。
  3. 它仅适用于动态链接程序,不适用于静态链接程序。
  4. 更新:如果要将呼叫链接到原始功能,可以执行以下操作:

    #define _GNU_SOURCE 
    
    #include <stdio.h>
    #include <unistd.h>
    #include <dlfcn.h>
    
    int usleep(useconds_t sec)
    {
        typedef int (*usleep_f)(useconds_t);
        static usleep_f real_usleep = NULL;
        if (!real_usleep)
            real_usleep = (usleep_f)dlsym(RTLD_NEXT, "usleep");
    
        printf("%d\n", (int)sec);
    
        if (...)
            return real_usleep(sec);
        else
            return 0;
    }
    

    如果你想避免GNU扩展(RTLD_NEXT是一个),你必须发现包含该函数的共享库的名称,例如:

    $ objdump -p pbucon.run | grep NEEDED
    NEEDED           libc.so.6
    

    然后,在函数中执行:

        if (!real_usleep)
        {
            void *libc_so = dopen("libc.so.6", RTLD_GLOBAL);
            real_usleep = (usleep_f)dlsym(libc_so, "usleep");
        }
    

答案 1 :(得分:2)

不确定。我假设说话,因为我没有程序或来源,但nanosleep()可能是通过调用sleep()来表示的。如果是我,我会使用objdump -d反汇编代码,看看我是否可以使用该代码和通过strace获取的信息来查明对sleep()(或其bvi的具体调用变体),例如围绕它的调用等。这不是微不足道的,但是可能的。如果你能做到这一点,你可以看到传入了什么参数(在x86上,它们被推入堆栈;在64位上,它们将在寄存器中),然后直接修改它们。如果它们是变量,您也可以通过这种方式跟踪它们。

如果您找到要编辑的位置,为了实际编辑二进制文件,您可以使用xxd之类的程序,甚至使用-r输出文件,更改单词,以及然后使用其xxd选项再次获取二进制文件。

编辑现在,objdump中的偏移量与您在objdump中看到的偏移量有所不同(我会忘记它是否始终如此)。这是因为xxd中显示的偏移量是虚拟地址,readelf -WS中显示的偏移量是文件中的实际偏移量。要协调此问题,您可以使用/bin/ls来显示文件的标题标题,例如(以$ readelf -WS /bin/ls | grep .text [13] .text PROGBITS 0000000000402460 002460 00c248 00 AX 0 0 16 为例):

PROGBITS

此处,相关信息是402460之后的两列。 .text2460部分的虚拟地址,这是存储二进制文件中可执行代码的位置,400000实际偏移量在文件中找到此部分的位置。减去这两个,你得到objdump(当然是十六进制)。现在,如果你回到Disassembly of section .text: 0000000000402460 <close_stdout-0x6460>: ,你应该找到几行代码:

.text

所以你看到402460(404260 - 400000)开始?在2460xxd的文件中查找此功能(和数据),您应该找到它!所以你在{{1}}中寻找的是objdump中虚拟地址的位置减去你发现的偏移量,如上所述。很抱歉忘了这个!