Como posso colocar uma máscara de bits em / dev / zero para que eu possa obter bytes diferentes de zero?

20

Como posso colocar uma máscara de bits em /dev/zero para que eu possa ter uma fonte não apenas para 0x00 mas também para qualquer byte entre 0x01 e 0xFF?

    
por Eduard Florinescu 10.06.2015 / 10:53

8 respostas

18

O código bash a seguir está configurado para funcionar com o byte sendo representado em binário . No entanto, você pode facilmente alterá-lo para lidar com ocatal , decimal ou hex simplesmente alterando o valor radix r de 2 a 8 , 10 ou 16 respectivamente e definindo b= de acordo.

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

EDIT - Ele manipula o intervalo completo de valores de bytes: hex 00 - FF (quando eu escrevi 00-7F abaixo, eu estava considerando apenas caracteres UTF-8 de byte único).

Se, por exemplo, você quiser apenas 4 bytes (caracteres no intervalo hexagonal 00-7F somente para 'ASCII' do UTF-8) , é possível canalizá-lo em cabeça : ... | head -c4

Saída (4 caracteres):

0000000: 10000000 10000000 10000000 10000000                    ....

Para ver a saída no formato de 8 bits, canalize-a para xxd (ou qualquer outro dump de byte de 1 e 0 *):
 por exemplo. b=10000000 e canalização para: ... | head -c4 | xxd -b

r=2; b=01111110
printf -vo '\%o' "$(($r#$b))"; </dev/zero tr '
~~~~
' "$o"
    
por 10.06.2015 / 11:43
18

Você não pode fazer isso facilmente.

Você pode considerar escrever seu próprio módulo de kernel fornecendo tal dispositivo. Eu não recomendo isso.

Você poderia escrever um pequeno programa C escrevendo um fluxo infinito de mesmos bytes em algum pipe (ou em stdout ) ou FIFO.

Você pode usar tr (1) para ler em /dev/zero e traduzir cada 0 byte para outra coisa.

Você pode usar talvez sim (1) , pelo menos se puder pagar ter novas linhas (ou então canalizar em tr -d '\n' ...)

    
por 10.06.2015 / 10:58
13

Bem, se você literalmente quer conseguir isso, você pode usar um Gancho LD_PRELOAD . A idéia básica é reescrever uma função da biblioteca C e usá-la em vez da normal.

Aqui está um exemplo simples em que sobrescrevemos a função read () para XOR o buffer de saída com 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);    
}

Uma implementação ingênua seria XOR 0x42 em todos os arquivos que lemos, o que teria conseqüências indesejáveis. A fim de resolver este problema, eu também conectei a função open () , fazendo com que ela buscasse o descritor de arquivo associado a / dev / zero. Então, nós apenas executamos o XOR em nossa função read () se fd == dev_zero_fd .

Uso:

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

Em termos de velocidade, o mais rápido que encontrei foi:

$ PERLIO=:unix perl -e '$s="" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]

Para comparação:

$ tr '
$ yes $'' | tr -d '\n' | pv -a > /dev/null
[26.7MiB/s]
' '' < /dev/zero | pv -a > /dev/null [ 765MiB/s] $ busybox tr '
$ dash -c 'while : ; do echo -n ""; done' | pv -a > /dev/null
[ 225KiB/s]
' '' < /dev/zero | pv -a > /dev/null [ 399MiB/s]

$ bash -c 'while : ; do echo -ne ""; done' | pv -a > /dev/null
[ 180KiB/s]

$ < /dev/zero pv -a > /dev/null
[5.56GiB/s]
$ cat /dev/zero | pv -a > /dev/null
[2.82GiB/s]
$ PERLIO=:unix perl -e '$s="" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]

$ tr '
$ yes $'' | tr -d '\n' | pv -a > /dev/null
[26.7MiB/s]
' '' < /dev/zero | pv -a > /dev/null [ 765MiB/s] $ busybox tr '
$ dash -c 'while : ; do echo -n ""; done' | pv -a > /dev/null
[ 225KiB/s]
' '' < /dev/zero | pv -a > /dev/null [ 399MiB/s]
    
por 11.06.2015 / 12:38
7

É meio inútil tentar bitmask / xor zero bytes, não é? Tomando um byte e xor ing com zero é um não-operacional.

Basta criar um loop que forneça os bytes desejados e colocá-lo atrás de um pipe ou pipe nomeado. Ele se comportará da mesma maneira que um dispositivo de caractere (não desperdiçará ciclos de CPU quando ocioso):

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

E se você quiser otimizá-lo, use o código C abaixo:

#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)); 
  }
}

compilar & correr

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

Teste de desempenho:

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

2.1GB / s na minha máquina (mesmo que ligeiramente mais rápido que cat /dev/zero | pv -a >/dev/null )

    
por 11.06.2015 / 10:22
5

Leia zeros, traduza cada zero para o seu padrão!

Lemos zero bytes de /dev/zero e usamos tr para aplicar uma máscara de bits a cada um dos bytes, traduzindo cada byte zero:

$ </dev/zero tr '
$ </dev/zero tr '
$ </dev/zero tr '
$ </dev/zero tr '
$ </dev/zero tr '
$ </dev/zero tr '%pre%0' '6' | pv -a >/dev/null
[ 913MB/s]

$ </dev/zero cat | pv -a >/dev/null        
[4.37GB/s]
0' '7' | head -c 10 | hexdump 0000000 ffff ffff ffff ffff ffff 000000a
0' '6' | head -c 10 ~~~~~~~~~~$
0' '6' | pv -a >/dev/null [ 913MB/s] $ </dev/zero cat | pv -a >/dev/null [4.37GB/s]
0' '7' | head -c 10 | hexdump 0000000 ffff ffff ffff ffff ffff 000000a
0' '6' | head -c 10 ~~~~~~~~~~$

Octal 176 é o código ascii de ~ , então nós obtemos 10 ~ . (O $ no final da saída indica no meu shell que não havia fim de linha - poderia parecer diferente para você)

Então, vamos criar 0xFF bytes: Hex 0xFF é octal 0377 . O zero inicial é deixado de fora para a linha de comandos tr ; No final, hexdump é usado para tornar a saída legível.

%pre%

Você precisa usar os códigos octal dos caracteres aqui, em vez do hexadecimal. Portanto, é o intervalo de 70 a octal 0xFF (o mesmo que ascii -x ).
Use ascii -o e ascii para obter uma tabela dos caracteres com números de índice hexadecimal ou octal.
(Para uma tabela com decimal e hexadecimal, apenas cat /dev/zero ).

Muito rápido

Ele roda razoavelmente rápido, comparado a apenas usar os zeros: tr é apenas quatro vezes mais rápido, enquanto pode fazer uso perfeito do buffer de E / S, que %code% não consegue.

%pre%     
por 11.06.2015 / 00:25
3

Depende do que você deseja fazer com os dados e da flexibilidade que deseja usar.

No pior caso, se você precisar de velocidade, você poderia fazer o mesmo que / dev / zero e apenas compilar o / dev / one, / dev / two, .. / dev / fourtytwo .. e assim por diante.

Na maioria dos casos, deve ser melhor criar os dados diretamente onde é necessário, portanto, dentro de um programa / script como uma constante. Com mais informações, as pessoas podem ajudá-lo melhor.

    
por 10.06.2015 / 22:46
1

Circuito do imprint printf

Reeplace \u00 com o byte desejado.

while true ; do printf "\u00" ; done | yourapp

Código C ++:

#include<cstdio>

int main(){
 char out=Byte;
 while(true)
 fwrite(&out,sizeof(out),1,stdout);
}

Compile: substitua Byte pelo valor desejado.

g++ -O3 -o bin file.cpp -D Byte=0x01

Use

./bin | yourapp

    
por 06.02.2016 / 08:33

Tags