ฉันจะใส่บิตมาสก์ได้อย่างไร/dev/zeroเพื่อให้สามารถมีแหล่งที่มาไม่เพียง แต่สำหรับ 0x00 แต่ยังสำหรับไบต์ระหว่าง 0x01 ถึง 0xFF ด้วย?
0x00ค่าเป็นค่าเฉพาะหรือเป็นค่าสุ่มใน0x00-0xFFช่วงหรือไม่
444444...ไม่ใช่แบบสุ่ม
ฉันจะใส่บิตมาสก์ได้อย่างไร/dev/zeroเพื่อให้สามารถมีแหล่งที่มาไม่เพียง แต่สำหรับ 0x00 แต่ยังสำหรับไบต์ระหว่าง 0x01 ถึง 0xFF ด้วย?
0x00ค่าเป็นค่าเฉพาะหรือเป็นค่าสุ่มใน0x00-0xFFช่วงหรือไม่
444444...ไม่ใช่แบบสุ่ม
คำตอบ:
ต่อไปนี้bashรหัสถูกตั้งค่าให้ทำงานร่วมกับไบต์ที่ถูก representred ในไบนารี แต่คุณสามารถเปลี่ยนมันในการจัดการocatal , ทศนิยมหรือหกเหลี่ยมโดยเพียงแค่การเปลี่ยนRadix r ค่าของ2 การ8, 10หรือ16ตามลำดับและการตั้งค่าb=ตาม
r=2; b=01111110
printf -vo '\\%o' "$(($r#$b))"; </dev/zero tr '\0' "$o"
แก้ไข - มันจัดการกับช่วงเต็มของค่าไบต์: hex 00 - FF (เมื่อฉันเขียน 00-7F ด้านล่างฉันกำลังพิจารณาอักขระ UTF-8 ไบต์เดียวเท่านั้น
ตัวอย่างเช่นหากคุณต้องการเพียง 4 ไบต์(อักขระในช่วง 00-7F hex ของ UTF-8 'ASCII'-only hex เท่านั้น)คุณสามารถไพพ์ไว้ในส่วนหัวได้ :... | head -c4
เอาท์พุท (4 ตัวอักษร):
~~~~
หากต้องการดูผลลัพธ์ในรูปแบบ 8 บิตให้ไพพ์ลงในxxd(หรือของอื่น ๆ1 และ 0 ของ byte dump *):
เช่น b=10000000และไปที่:... | head -c4 | xxd -b
0000000: 10000000 10000000 10000000 10000000 ....
o=$(printf ...)สำหรับบรรทัดที่สอง?
-vเป็นสาเหตุที่ทำให้การส่งออก Tthe การตั้งโดยตรงตัวแปรชื่อทันทีหลังจากนั้น ในกรณีนี้ชื่อของตัวแปรคือo(สำหรับฐานแปด ) - โปรดทราบว่า-vตัวเลือกนี้ใช้กับเวอร์ชันshell-builtinของprintf(ไม่ใช่รุ่น/ usr / bin / printf )
-vตัวเลือกที่ทำให้แน่ใจว่าตัวแปรได้รับการตั้งค่าให้ตรงกับสิ่งที่คุณระบุ $(...)แปลงเอาต์พุตก่อน ซึ่งเป็นเหตุผลที่o=$(printf '\n')จะไม่ได้มีผลที่คุณอาจคาดหวังในขณะที่printf -vo '\n'ไม่ (ไม่สำคัญที่นี่เนื่องจากผลลัพธ์ที่นี่อยู่ในรูปแบบที่ไม่ได้รับผลกระทบจากการเปลี่ยนแปลงดังกล่าว แต่ถ้าคุณไม่รู้-vตัวเลือกสิ่งนี้อาจเป็นประโยชน์ที่จะรู้)
คุณไม่สามารถทำเช่นนั้นได้อย่างง่ายดาย
คุณอาจลองเขียนโมดูลเคอร์เนลของคุณเองเพื่อจัดหาอุปกรณ์ดังกล่าว ฉันไม่แนะนำ
คุณสามารถเขียนโปรแกรม C เล็ก ๆ ที่เขียนกระแสอนันต์ของไบต์เดียวกันบนไพพ์ (หรือบนstdout) หรือ FIFO
คุณสามารถใช้tr (1)เพื่ออ่าน/dev/zeroและแปลทุกๆ 0 ไบต์เป็นอย่างอื่น
คุณสามารถใช้ใช่ (1)อย่างน้อยถ้าคุณสามารถมีบรรทัดใหม่ (หรืออื่น ๆ ท่อลงในtr -d '\n'... )
yes 1 | tr -d $'\n'สำหรับเรื่องที่
yesกระแส\nตัวอักษร อีกทางเลือกหนึ่งที่จัดการ\nคือ: yes '' | tr '\n' "$c"- ซึ่ง$cสามารถใช้อักขระ ASCII แบบเต็มรูปแบบได้
yes 1 | tr -d $'\n'ผมไม่แน่ใจว่าวิธีการที่คุณตีความความคิดเห็นของฉันเพื่ออะไรหมายถึงอื่นที่ไม่ใช่ตัวอักษรแสดงออกคงที่ ฉันคิดว่าคุณสามารถใช้เชลล์ที่ไม่ได้ใช้$''แบ็กสแลชทรีทเม้นต์หรือคุณอาจลองหาโลแคลที่มีการเปลี่ยนแปลงtr -d $'\n'แต่ฉันยังไม่พบมัน
yes 1 | tr -d $'\n'จะพิมพ์สตรีมของ1ตัวละครอย่างมีความสุขและเกือบทุกค่าไบต์เดียว แต่ไม่สามารถพิมพ์\nตัวอักษรได้ OP ต้องการให้สามารถจัดการค่าไบต์ทั้งหมด"ระหว่าง 0x01 ถึง 0xFF"
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
ดีถ้าคุณอย่างแท้จริงต้องการเพื่อให้บรรลุนี้คุณสามารถใช้เบ็ด LD_PRELOAD แนวคิดพื้นฐานคือการเขียนฟังก์ชั่นใหม่จากไลบรารี C และใช้งานแทนการใช้งานปกติ
นี่คือตัวอย่างง่ายๆที่เราแทนที่ฟังก์ชั่นread ()เพื่อ XOR บัฟเฟอร์ผลลัพธ์ด้วย 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);
}
การนำไปปฏิบัติที่ไร้เดียงสาจะมี XOR 0x42 ในทุกไฟล์ที่เราอ่านซึ่งจะมีผลที่ไม่พึงประสงค์ เพื่อที่จะแก้ปัญหานี้ฉันยังได้เชื่อมต่อกับฟังก์ชั่นopen ()ทำให้มันสามารถดึงไฟล์ descriptor ที่เกี่ยวข้องกับ / dev / zero จากนั้นเราจะดำเนินการกับแฮคเกอร์ในฟังก์ชั่นread ()ของเรา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
ในแง่ของความเร็วที่เร็วที่สุดที่ฉันพบคือ:
$ PERLIO=:unix perl -e '$s="\1" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]
สำหรับการเปรียบเทียบ:
$ tr '\0' '\1' < /dev/zero | pv -a > /dev/null
[ 765MiB/s]
$ busybox tr '\0' '\1' < /dev/zero | pv -a > /dev/null
[ 399MiB/s]
$ yes $'\1' | tr -d '\n' | pv -a > /dev/null
[26.7MiB/s]
$ dash -c 'ขณะที่:; ทำเสียงสะท้อน -n "\ 1"; เสร็จสิ้น '| pv -a> / dev / null [225KiB / s]
$ bash -c 'ขณะที่:; ทำ echo -ne "\ 1"; เสร็จสิ้น '| 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]
perlให้ผลตอบแทน 2.13GiB ในขณะที่< /dev/zeroให้ผลผลิต 8.73GiB สิ่งใดที่มีผลต่อประสิทธิภาพการทำงาน
perlก็เร็วกว่าโซลูชั่นอื่น ๆ เสมอ ฉันได้ปริมาณงานเท่ากันกับโปรแกรม C ที่คอมไพล์แล้ว เกณฑ์มาตรฐานนั้นมีมากพอ ๆ กับแอปพลิเคชั่นเหมือนกับตัวกำหนดตารางเวลาของระบบที่นี่ สิ่งที่ทำให้แตกต่างที่สุดคือขนาดของบัฟเฟอร์ที่เขียน
cat /dev/zero| pv -a >/dev/nullจะให้คุณประมาณ 2 GiB ต่อวินาทีเช่นกัน (ในระบบของฉันในขณะที่< /dev/zero) ให้ฉันประมาณ 6GiBps
Linux ProBook 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/Linuxใช้ Intel i5 Core อยู่ภายใน
มันไม่มีประโยชน์ที่จะลองแล้ว bitmask / xor zero bytes ใช่ไหม? การไบต์และxoring กับศูนย์เป็น no-op
เพียงสร้างลูปที่ให้ไบต์ที่คุณต้องการและวางไว้ข้างหลังไพพ์หรือไพพ์ที่มีชื่อ มันจะทำงานเหมือนกับอุปกรณ์ตัวอักษร (จะไม่เสียรอบ 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 / sบนเครื่องของฉัน (เร็วกว่าเล็กน้อยcat /dev/zero | pv -a >/dev/null)
argc == 1+1แทนagrc == 2?
0 XOR X == X.
เราอ่านศูนย์ไบต์ออกมา/dev/zeroและใช้trเพื่อนำบิตมาส์กไปใช้กับแต่ละไบต์โดยการแปลแต่ละไบต์เป็นศูนย์:
$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$
Octal 176 เป็นรหัส ASCII ของ~เราจึงได้รับ ~10 ( $ตอนท้ายของเอาต์พุตระบุในเชลล์ของฉันว่าไม่มีบรรทัดปลาย - มันอาจดูแตกต่างสำหรับคุณ)
ดังนั้นขอสร้าง0xFFไบต์: Hex เป็นฐานแปด0xFF 0377ศูนย์นำหน้าจะถูกปล่อยทิ้งไว้สำหรับtrบรรทัดคำสั่ง ในตอนท้ายhexdumpใช้เพื่อให้เอาต์พุตอ่านได้
$ </dev/zero tr '\000' '\377' | head -c 10 | hexdump
0000000 ffff ffff ffff ffff ffff
000000a
คุณต้องใช้รหัสฐานแปดของอักขระที่นี่แทนเลขฐานสิบหก ดังนั้นมันคือช่วงจาก\000ถึงฐานแปด\377(เหมือน0xFF)
ใช้ascii -xและascii -oเพื่อรับตารางของตัวละครที่มีหมายเลขดัชนีเลขฐานสิบหกหรือฐานแปด
(สำหรับตารางที่มีทศนิยมและเลขฐานสิบหกเพียงascii)
มันทำงานได้ค่อนข้างเร็วเมื่อเทียบกับการใช้ศูนย์: เร็วcat /dev/zeroเพียงสี่เท่าในขณะที่มันสามารถใช้งานบัฟเฟอร์ IO ได้อย่างสมบูรณ์แบบซึ่งtrไม่สามารถทำได้
$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]
$ </dev/zero cat | pv -a >/dev/null
[4.37GB/s]
ขึ้นอยู่กับสิ่งที่คุณต้องการทำกับข้อมูลและความยืดหยุ่นที่คุณต้องการใช้
กรณีที่เลวร้ายที่สุดถ้าคุณต้องการความเร็วคุณสามารถทำเช่นเดียวกับ / dev / ศูนย์และเพียงแค่รวบรวม / dev / หนึ่ง / dev / สอง, .. / dev / fourtytwo .. และอื่น ๆ บนอุปกรณ์
ในกรณีส่วนใหญ่ควรสร้างข้อมูลโดยตรงที่ต้องการได้ดีกว่าดังนั้นภายในโปรแกรม / สคริปต์เป็นค่าคงที่ ด้วยข้อมูลที่ผู้คนมากมายสามารถช่วยคุณได้ดียิ่งขึ้น
พิมพ์วนวน printf
รีเฟรช\u00ด้วยไบต์ที่คุณต้องการ
while true ; do printf "\u00" ; done | yourapp
รหัส C ++:
#include<cstdio>
int main(){
char out=Byte;
while(true)
fwrite(&out,sizeof(out),1,stdout);
}
คอมไพล์:ใส่ใหม่Byteด้วยค่าที่คุณต้องการ
g++ -O3 -o bin file.cpp -D Byte=0x01
ใช้
./bin | yourapp