ฉันจะใส่บิตมาสก์ได้อย่างไร/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 ใช่ไหม? การไบต์และxor
ing กับศูนย์เป็น 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