如何在 /dev/zero 上放置位掩码,以便可以获得非零的字节?

如何在 /dev/zero 上放置位掩码,以便可以获得非零的字节?

如何添加位掩码,/dev/zero以便不仅可以获取 0x00 的源,还可以获取 0x01 和 0xFF 之间的任何字节的源?

答案1

以下bash代码设置为与表示的字节一起使用二进制。但是您可以轻松更改它来处理奥卡塔尔,小数或者十六进制通过简单地改变基数 r2 的 值81016分别并进行b=相应设置。

r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"

编辑- 它确实处理全系列字节值:十六进制 00-FF(当我在下面写00-7F时,我只考虑单字节UTF-8字符)。

例如,如果您只需要 4 个字节(UTF-8 'ASCII'-only 十六进制 00-7F 范围内的字符),你可以通过管道将其输入:... | head -c4

输出(4 个字符):

~~~~

要查看 8 位格式的输出,请将其通过管道传输到xxd(或任何其他1 和 0字节转储*):
例如。b=10000000并通过管道输送至:... | head -c4 | xxd -b

0000000: 10000000 10000000 10000000 10000000                    ....

答案2

你不能轻易做到这一点。

您可以考虑编写自己的内核模块来提供此类设备。我不建议这样做。

您可以编写一个微型 C 程序,在某个管道(或 )或 FIFO 上写入相同字节的无限流stdout

你可以使用TR(1)读取/dev/zero每个 0 字节并将其转换为其他字节。

你也许可以用是(1),至少如果你能负担得起换行符(或者通过管道将其输入tr -d '\n'......)

答案3

好吧,如果你字面上地想要实现这一点,你可以使用LD_PRELOAD 钩子。基本思想是重写 C 库中的函数并使用它来代替普通函数。

这是一个简单的例子,我们重写读()函数将输出缓冲区与 0x42 进行异或。

#define _GNU_SOURCE
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <dlfcn.h> 
#include <unistd.h>

static int dev_zero_fd = -1;

int open64(const char *pathname, int flags)
{
    static int (*true_open64)(const char*, int) = NULL;
    if (true_open64 == NULL) {
        if ((true_open64 = dlsym(RTLD_NEXT, "open64")) == NULL) {
            perror("dlsym");
            return -1;
        }        
    }
    int ret = true_open64(pathname, flags);
    if (strcmp(pathname, "/dev/zero") == 0) {
        dev_zero_fd = ret;
    }
    return ret;
}


ssize_t read(int fd, void *buf, size_t count)
{
    static ssize_t (*true_read)(int, void*, size_t) = NULL;
    if (true_read == NULL) {
        if ((true_read = dlsym(RTLD_NEXT, "read")) == NULL) {
            perror("dlsym");
            return -1;
        }        
    }    

    if (fd == dev_zero_fd) {
        int i;
        ssize_t ret = true_read(fd, buf, count);    
        for (i = 0; i < ret; i++) {
            *((char*)buf + i) ^= 0x42;
        }
        return ret;
    }

    return true_read(fd, buf, count);    
}

一个幼稚的实现会对我们读取的每个文件进行异或 0x42,这会产生不良后果。为了解决这个问题,我还挂了打开()函数,使其获取与 /dev/zero 关联的文件描述符。然后,我们只对我们的读()函数如果fd == dev_zero_fd.

用法:

$ gcc hook.c -ldl -shared -o hook.so
$ LD_PRELOAD=$(pwd)/hook.so bash #this spawns a hooked shell
$ cat /dev/zero
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

答案4

尝试位掩码/异或零字节是毫无意义的,不是吗?获取一个字节并xor用零对其进行处理是无操作的。

只需创建一个循环,为您提供所需的字节,并将其放在管道或命名管道后面。它的行为与字符设备几乎相同(空闲时不会浪费 CPU 周期):

mkfifo pipe
while : ; do echo -n "a"; done > pipe &

如果你想对其进行超级优化,你可以使用下面的 C 代码:

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) { 
  char c = argc == 1+1 ? argv[1][0] : 'y';

  char buff[BUFSIZ];
  memset(buff, c, BUFSIZ);

  for(;;){ 
    write(1, buff, sizeof(buff)); 
  }
}

编译并运行

$ CFLAGS=-O3 make loop
./loop "$the_byte_you_want" > pipe

性能测试:

./loop 1 | pv -a >/dev/null 

2.1GB/秒在我的机器上(甚至比 稍快cat /dev/zero | pv -a >/dev/null

相关内容