x86 용 명령어 버퍼가있는 경우 opcode가 SSE 명령어의 범위 내에 있는지 확인하지 않고도 명령어가 SSE 명령어인지 쉽게 확인할 수 있습니다. 이 말은 공통 명령 접두사 나 프로세서 상태 (예 : 레지스터)를 확인할 수 있다는 뜻입니까?버퍼의 SSE 명령어
답변
더 :
이 명령의 형식은 Intel 64 and IA-32 Architectures Software Developer's Manual Combined Volumes 2A and 2B: Instruction Set Reference, A-Z의 2 장에 설명되어 있습니다.하지 문제가되는 부분 중 하나는 접두사입니다. 일부 SSE 명령어 (66
F2
F3
)는 다른 opcode (오퍼랜드 크기 오버라이드, REPNZ
및 REPZ
)와는 다른 의미를 가지지 만 일부 명령어는 필수입니다.
0f 58 c0 addps xmm0,xmm0
66 0f 58 c0 addpd xmm0,xmm0
f3 0f 58 c0 addss xmm0,xmm0
f2 0f 58 c0 addsd xmm0,xmm0
기본적으로 두 가지를 추가하는 것 같다 :
은 XMM 함께 등록 (출력 objdump -D -b binary -m i386:x86-64:intel --insn-width=12
얻을)이 추가 이러한 4 개 형태를 고려, 접두사가 서로 다른 지침을 구분하는 데 사용되는 방법을 보려면 double precision 버전을 선택하면 F3
(repz
)은 압축 단일 버전을 선택하고 마지막으로 F2
(repnz
)은 압축 된 double 버전을 선택합니다.
또한 때때로 결합 될 수 있으며 64 비트 모드에서는 REX 접두사 (pg. 2-9)에 대해서도 걱정해야합니다. 다음은 64 비트 모드에서 서로 다른 접두어를 사용하는 대략 동일한 기본 명령어의 서로 다른 버전을 보여주는 예입니다. 당신은 AVX 명령에 대해 신경 나도 몰라하지만 난 예를 들어 어쨌든 하나를 포함 :
이 가0f 51 ca sqrtps xmm1,xmm2
0f 51 0c 85 0a 00 00 00 sqrtps xmm1,XMMWORD PTR [rax*4+0xa]
65 0f 51 0c 85 0a 00 00 00 sqrtps xmm1,XMMWORD PTR gs:[rax*4+0xa]
67 0f 51 0c 85 0a 00 00 00 sqrtps xmm1,XMMWORD PTR [eax*4+0xa]
65 67 0f 51 0c 85 0a 00 00 00 sqrtps xmm1,XMMWORD PTR gs:[eax*4+0xa]
f0 65 67 0f 51 0c 85 0a 00 00 00 lock sqrtps xmm1,XMMWORD PTR gs:[eax*4+0xa]
c5 fd 51 ca vsqrtpd ymm1,ymm2
c5 fc 51 0c 85 0a 00 00 00 vsqrtps ymm1,YMMWORD PTR [rax*4+0xa]
65 c5 fc 51 0c 85 0a 00 00 00 vsqrtps ymm1,YMMWORD PTR gs:[rax*4+0xa]
67 c5 fc 51 0c 85 0a 00 00 00 vsqrtps ymm1,YMMWORD PTR [eax*4+0xa]
65 67 c5 fc 51 0c 85 0a 00 00 00 vsqrtps ymm1,YMMWORD PTR gs:[eax*4+0xa]
f0 65 67 c5 fc 51 0c 85 0a 00 00 00 lock vsqrtps ymm1,YMMWORD PTR gs:[eax*4+0xa]
가
그래서 지금까지 내가 항상 결정하기 위해 모든 접두사를 반복 할 것입니다 볼 수있는 명령이있는 경우 SSE 명령.
업데이트 : 추가로 복잡한 것은 ModRM 인코딩 만 다른 지침이 있다는 것입니다. 고려 :
df 00 fild WORD PTR [rax] # Non-SSE instruction: DF /0
df 08 fisttp WORD PTR [rax] # SSE instruction: DF /1
그들은 그것이 opcode map를 사용하는 가장 쉬운 인코딩 할 수있는 이러한 모든 다른 방법을 찾을 수 있습니다.
어쨌든 나는 디스어셈블러를 쓰는 것을 보았 기 때문에 그것이 무엇이 필요한지 보는 재미있는 도전이 될 것이라고 생각했습니다. 그것은 분명히 내가 그것을 보장 할 수는 없지만 보장하지는 않지만, 대부분의 SSE 지침을 찾아야한다. 위의 opcode 맵을 코드가 통과하는 일련의 테스트로 변환했습니다 (tests.c - 인라인하기에 너무 큼). 이 코드는 opcode 인코딩의 16 진수를 포함하는 일련의 텍스트 문자열을 테스트합니다 (첫 번째 16 진수가 아닌 숫자에서 구문 분석을 중지합니다. 문자열의 마지막 문자는 SSE 명령어인지 여부를 나타냄).
먼저 모든 접두어를 검색 한 다음 opcode 테이블을 사용하여 멀티 바이트 opcode에 필요한 중첩 테이블을 처리하는 추가 로직과 일치하는지 테스트하고 다음 modrm 바이트의 숫자와 일치시킬 필요가 있는지 테스트합니다.
ssedetect.c :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include "inst_table.h"
enum { PREFIX_66=OP_66_SSE, PREFIX_F2=OP_F2_SSE, PREFIX_F3=OP_F3_SSE };
static int check_prefixes(int prefixes, int op_type) {
if (op_type & OP_ALWAYS_SSE) return 1;
if ((op_type & OP_66_SSE) && (prefixes & PREFIX_66)) return 1;
if ((op_type & OP_F2_SSE) && (prefixes & PREFIX_F2)) return 1;
if ((op_type & OP_F3_SSE) && (prefixes & PREFIX_F3)) return 1;
return 0;
}
int isInstructionSSE(const uint8_t* code, int length)
{
int position = 0;
// read prefixes
int prefixes = 0;
while (position < length) {
uint8_t b = code[position];
if (b == 0x66) {
prefixes |= PREFIX_66;
position++;
} else if (b == 0xF2) {
prefixes |= PREFIX_F2;
position++;
} else if (b == 0xF3) {
prefixes |= PREFIX_F3;
position++;
} else if (b >= 0x40 && b <= 0x4F) {
//prefixes |= PREFIX_REX;
position++;
break; // opcode must follow REX
} else if (b == 0x2E || b == 0x3E || b == 0x26 || b == 0x36 || b == 0x64 || b == 0x65 || b == 0x67 || b == 0xF0) {
// ignored prefix
position++;
} else {
break;
}
}
// read opcode
const uint16_t* op_table = op;
int op_length = 0;
while (position < length) {
uint8_t b = code[position];
uint16_t op_type = op_table[b];
if (op_type & OP_EXTENDED) {
op_length++;
position++;
// hackish
if (op_length == 1 && b == 0x0F) op_table = op_0F;
else if (op_length == 2 && b == 0x01) op_table = op_0F_01;
else if (op_length == 2 && b == 0x38) op_table = op_0F_38;
else if (op_length == 2 && b == 0x3A) op_table = op_0F_3A;
else { printf("\n\n%2.2X\n",b); abort(); }
} else if (op_type & OP_DIGIT) {
break;
} else {
return check_prefixes(prefixes, op_type);
}
}
// optionally read a digit
// find digits we need can match in table
uint8_t match_digits = (op_table[code[position]] & OP_DIGIT_MASK) >> OP_DIGIT_SHIFT;
// consume the byte
op_length++;
position++;
if (position >= length) {
return 0;
}
uint8_t digit = (code[position]>>3)&7; // reg part of modrm
return (match_digits & (1 << digit)) != 0;
}
static int read_code(const char* str, uint8_t** code, int* length)
{
int size = 1000;
*length = 0;
*code = malloc(size);
if (!*code) {
printf("out of memory\n");
return 0;
}
while (*str) {
char* endptr;
unsigned long val = strtoul(str, &endptr, 16);
if (str == endptr) {
break;
}
if (val > 255) {
printf("%lX is out of range\n", val);
goto error;
return 0;
}
(*code)[*length] = (uint8_t)val;
if (++*length >= size) {
printf("needs resize, not implemented\n");
goto error;
}
str = endptr;
}
if (*length == 0) {
printf("No instruction bytes found\n");
goto error;
}
return 1;
error:
free(*code);
return 0;
}
static void test(const char* str)
{
uint8_t* code;
int length;
if (!read_code(str, &code, &length)) {
puts(str);
exit(1);
}
char is_sse = isInstructionSSE(code, length) ? 'Y' : 'N';
char should_be_sse = str[strlen(str)-1];
free(code);
if (should_be_sse != is_sse) {
printf("(%c) %c %s\n", should_be_sse, is_sse, str);
exit(1);
}
}
int main()
{
#include "tests.c"
test("48 ba 39 00 00 00 00 00 00 00 # movabs rdx,0x39 N");
test("48 b8 00 00 00 00 00 00 00 00 # movabs rax,0x0 N");
test("48 b9 14 00 00 00 00 00 00 00 # movabs rcx,0x14 N");
test("48 6b c0 0a # imul rax,rax,0xa N");
test("48 83 ea 30 # sub rdx,0x30 N");
test("48 01 d0 # add rax,rdx N");
test("48 ff c9 # dec rcx N");
test("75 f0 # jne 0x1e N");
test("0f 51 ca # sqrtps xmm1,xmm2 Y");
test("0f 51 0c 85 0a 00 00 00 # sqrtps xmm1,XMMWORD PTR [rax*4+0xa] Y");
test("65 0f 51 0c 85 0a 00 00 00 # sqrtps xmm1,XMMWORD PTR gs:[rax*4+0xa] Y");
test("67 0f 51 0c 85 0a 00 00 00 # sqrtps xmm1,XMMWORD PTR [eax*4+0xa] Y");
test("65 67 0f 51 0c 85 0a 00 00 00 # sqrtps xmm1,XMMWORD PTR gs:[eax*4+0xa] Y");
test("f0 65 67 0f 51 0c 85 0a 00 00 00 # lock sqrtps xmm1,XMMWORD PTR gs:[eax*4+0xa] Y");
test("f0 65 67 f3 43 0f 5c 8c 81 2a 2a 00 00 # lock subss xmm1, [gs:r8d*4+r9d+0x2A2A] Y");
test("0f 58 c0 # addps xmm0,xmm0 Y");
test("66 0f 58 c0 # addpd xmm0,xmm0 Y");
test("f3 0f 58 c0 # addss xmm0,xmm0 Y");
test("f2 0f 58 c0 # addsd xmm0,xmm0 Y");
test("df 04 25 2c 00 00 00 # fild WORD PTR ds:0x2c N");
test("df 0c 25 2c 00 00 00 # fisttp WORD PTR ds:0x2c Y");
test("67 0f ae 10 # ldmxcsr DWORD PTR [eax] Y");
test("67 0f ae 18 # stmxcsr DWORD PTR [eax] Y");
test("0f ae 00 # fxsave [rax] N");
test("0f ae e8 # lfence Y");
test("0f ae f0 # mfence Y");
test("0f ae f8 # sfence Y");
test("67 0f ae 38 # clflush BYTE PTR [eax] Y");
test("67 0f 18 00 # prefetchnta BYTE PTR [eax] Y");
test("0f 18 0b # prefetcht0 BYTE PTR [rbx] Y");
test("67 0f 18 11 # prefetcht1 BYTE PTR [ecx] Y");
test("0f 18 1a # prefetcht2 BYTE PTR [rdx] Y");
test("df 08 # fisttp WORD PTR [rax] Y");
test("df 00 # fild WORD PTR [rax] N");
printf("All tests passed\n");
return 0;
}
inst_table.h :
// Table Element format:
// Bit: 0 SSE instruction if 66 prefix
// 1 SSE instruction if F2 prefix
// 2 SSE instruction if F3 prefix
// 3 Extended table
// 4 Instruction is always SSE
// 5 SSE instruction if ModRM byte matches digit(s)
// 6 -----
// 7 -----
// 8 SSE if ModRM has reg = 0
// 9 SSE if ModRM has reg = 1
// .
// . That is it matches instructoins on the form XX XX /digit
// .
// 15 SSE if modRM has reg = 7
#define OP_66_SSE 0x0001 // SSE if 66 prefix
#define OP_F2_SSE 0x0002 // SSE if F2 prefix
#define OP_F3_SSE 0x0004 // SSE if F3 prefix
#define OP_EXTENDED 0x0008 // continue with extended table
#define OP_ALWAYS_SSE 0x0010
#define OP_DIGIT 0x0020
#define OP_DIGIT_MASK 0xFF00
#define OP_DIGIT_SHIFT 8
#define OP_MATCH_DIGIT(d) (OP_DIGIT | (1 << (d + OP_DIGIT_SHIFT)))
static const uint16_t op[256] = {
[0x0F] = OP_EXTENDED,
[0x90] = OP_F3_SSE,
[0xDB] = OP_MATCH_DIGIT(1), // DB /1: FISTTP
[0xDD] = OP_MATCH_DIGIT(1),
[0xDF] = OP_MATCH_DIGIT(1),
};
static const uint16_t op_0F[256] = {
[0x01] = OP_EXTENDED,
[0x10] = OP_ALWAYS_SSE, // 0F 10 MOVUPS, F3 0F 10 MOVSS ...
[0x11] = OP_ALWAYS_SSE,
[0x12] = OP_ALWAYS_SSE,
[0x13] = OP_ALWAYS_SSE,
[0x14] = OP_ALWAYS_SSE,
[0x15] = OP_ALWAYS_SSE,
[0x16] = OP_ALWAYS_SSE,
[0x17] = OP_ALWAYS_SSE,
[0x18] = OP_MATCH_DIGIT(0)|OP_MATCH_DIGIT(1)|OP_MATCH_DIGIT(2)|OP_MATCH_DIGIT(3),
[0x28] = OP_ALWAYS_SSE,
[0x29] = OP_ALWAYS_SSE,
[0x2A] = OP_ALWAYS_SSE,
[0x2B] = OP_ALWAYS_SSE,
[0x2C] = OP_ALWAYS_SSE,
[0x2D] = OP_ALWAYS_SSE,
[0x2E] = OP_ALWAYS_SSE,
[0x2F] = OP_ALWAYS_SSE,
[0x38] = OP_EXTENDED,
[0x3A] = OP_EXTENDED,
[0x50] = OP_ALWAYS_SSE,
[0x51] = OP_ALWAYS_SSE,
[0x52] = OP_ALWAYS_SSE,
[0x53] = OP_ALWAYS_SSE,
[0x54] = OP_ALWAYS_SSE,
[0x55] = OP_ALWAYS_SSE,
[0x56] = OP_ALWAYS_SSE,
[0x57] = OP_ALWAYS_SSE,
[0x58] = OP_ALWAYS_SSE,
[0x59] = OP_ALWAYS_SSE,
[0x5A] = OP_ALWAYS_SSE,
[0x5B] = OP_ALWAYS_SSE,
[0x5C] = OP_ALWAYS_SSE,
[0x5D] = OP_ALWAYS_SSE,
[0x5E] = OP_ALWAYS_SSE,
[0x5F] = OP_ALWAYS_SSE,
[0x60] = OP_66_SSE,
[0x61] = OP_66_SSE,
[0x62] = OP_66_SSE,
[0x63] = OP_66_SSE,
[0x64] = OP_66_SSE,
[0x65] = OP_66_SSE,
[0x66] = OP_66_SSE,
[0x67] = OP_66_SSE,
[0x68] = OP_66_SSE,
[0x69] = OP_66_SSE,
[0x6A] = OP_66_SSE,
[0x6B] = OP_66_SSE,
[0x6C] = OP_66_SSE,
[0x6D] = OP_66_SSE,
[0x6E] = OP_66_SSE,
[0x6F] = OP_66_SSE | OP_F3_SSE,
[0x70] = OP_ALWAYS_SSE,
[0x71] = OP_66_SSE,
[0x72] = OP_66_SSE,
[0x73] = OP_66_SSE,
[0x74] = OP_66_SSE,
[0x75] = OP_66_SSE,
[0x76] = OP_66_SSE,
[0x77] = OP_66_SSE,
[0x78] = OP_66_SSE,
[0x79] = OP_66_SSE,
[0x7A] = OP_66_SSE,
[0x7B] = OP_66_SSE,
[0x7C] = OP_66_SSE | OP_F2_SSE,
[0x7D] = OP_66_SSE | OP_F2_SSE,
[0x7E] = OP_66_SSE | OP_F3_SSE,
[0x7F] = OP_66_SSE | OP_F3_SSE,
[0xAE] = OP_MATCH_DIGIT(2)|OP_MATCH_DIGIT(3)|OP_MATCH_DIGIT(5)|OP_MATCH_DIGIT(6)|OP_MATCH_DIGIT(7),
[0xC2] = OP_ALWAYS_SSE,
[0xC3] = OP_ALWAYS_SSE,
[0xC4] = OP_ALWAYS_SSE,
[0xC5] = OP_ALWAYS_SSE,
[0xC6] = OP_ALWAYS_SSE,
[0xD0] = OP_66_SSE | OP_F2_SSE,
[0xD1] = OP_66_SSE,
[0xD2] = OP_66_SSE,
[0xD3] = OP_66_SSE,
[0xD4] = OP_ALWAYS_SSE,
[0xD5] = OP_66_SSE,
[0xD6] = OP_66_SSE | OP_F2_SSE | OP_F3_SSE,
[0xD7] = OP_ALWAYS_SSE,
[0xD8] = OP_66_SSE,
[0xD9] = OP_66_SSE,
[0xDA] = OP_ALWAYS_SSE,
[0xDB] = OP_66_SSE,
[0xDC] = OP_66_SSE,
[0xDD] = OP_66_SSE,
[0xDE] = OP_ALWAYS_SSE,
[0xDF] = OP_66_SSE,
[0xE0] = OP_ALWAYS_SSE,
[0xE1] = OP_66_SSE,
[0xE2] = OP_66_SSE,
[0xE3] = OP_ALWAYS_SSE,
[0xE4] = OP_ALWAYS_SSE,
[0xE5] = OP_66_SSE,
[0xE6] = OP_66_SSE | OP_F2_SSE | OP_F3_SSE,
[0xE7] = OP_ALWAYS_SSE,
[0xE8] = OP_66_SSE,
[0xE9] = OP_66_SSE,
[0xEA] = OP_ALWAYS_SSE,
[0xEB] = OP_66_SSE,
[0xEC] = OP_66_SSE,
[0xED] = OP_66_SSE,
[0xEE] = OP_ALWAYS_SSE,
[0xEF] = OP_66_SSE,
[0xF0] = OP_F2_SSE,
[0xF1] = OP_66_SSE,
[0xF2] = OP_66_SSE,
[0xF3] = OP_66_SSE,
[0xF4] = OP_ALWAYS_SSE,
[0xF5] = OP_66_SSE,
[0xF6] = OP_ALWAYS_SSE,
[0xF7] = OP_ALWAYS_SSE,
[0xF8] = OP_66_SSE,
[0xF9] = OP_66_SSE,
[0xFA] = OP_66_SSE,
[0xFB] = OP_ALWAYS_SSE,
[0xFC] = OP_66_SSE,
[0xFD] = OP_66_SSE,
[0xFE] = OP_66_SSE,
};
static const uint16_t op_0F_01[256] = {
[0xC8] = OP_ALWAYS_SSE, // 0F 01 C8: MONITOR
[0xC9] = OP_ALWAYS_SSE,
};
static const uint16_t op_0F_38[256] = {
[0xF0] = OP_F2_SSE, // F2 0F 38 F0: CRC32
[0xF1] = OP_F2_SSE,
};
static const uint16_t op_0F_3A[256] = {
[0x08] = OP_66_SSE, // 66 0F 3A 08: ROUNDPS
[0x09] = OP_66_SSE,
[0x0A] = OP_66_SSE,
[0x0B] = OP_66_SSE,
[0x0C] = OP_66_SSE,
[0x0D] = OP_66_SSE,
[0x0E] = OP_66_SSE,
[0x0F] = OP_ALWAYS_SSE,
[0x14] = OP_66_SSE,
[0x15] = OP_66_SSE,
[0x16] = OP_66_SSE,
[0x17] = OP_66_SSE,
[0x20] = OP_66_SSE,
[0x21] = OP_66_SSE,
[0x22] = OP_66_SSE,
[0x40] = OP_66_SSE,
[0x41] = OP_66_SSE,
[0x42] = OP_66_SSE,
[0x60] = OP_66_SSE,
[0x61] = OP_66_SSE,
[0x62] = OP_66_SSE,
[0x63] = OP_66_SSE,
};
SSE 프리픽스가 없습니다. 일부 SSE 명령어는 0F로 시작하고 일부는 F3으로 시작하지만 일부는 0F 및 F3 명령어가 SSE 명령어가 아닙니다. 명령어가 SSE인지 여부를 알기 위해서는보다 포괄적 인 디코더가 필요합니다. x86 명령어는 가변 길이이므로 어쨌든 필요합니다. 당신이 대답은 예 또는입니다 쉽게 정의하는 방법에 따라
0F 두 바이트 지시하고 모든 SSE 명령어 검사를 많이 배제 두 바이트입니다. 또한 SSE 명령어 (많은 명령어)는 0x66 0xF2 0xF3부터 시작합니다. 지금까지 내가 가지고있는 것은 접두사가있는 2 바이트 명령어 인 경우 확실히 SSE이지만 일부 SSE 명령어에는 접두어가없고 그 중 일부는 문제가되는 것입니다. –
- 1. AltiVec에 MMX/SSE 명령어 포팅하기
- 2. SSE 프리 페치 명령어 크기를 결정하는 방법은 무엇입니까?
- 3. SSE 명령어로 복제 - XMM 레지스터 확장
- 4. 로드 상수가 SSE 레지스터에 뜬다
- 5. /proc/cpuinfo에서 GCC 용 sse 스위치 빌드
- 6. SSE 마이크로 최적화 명령 주문
- 7. Visual Studio 2008에서 CMake를 사용하여 SSE/SSE2 명령어 세트를 활성화하려면 어떻게해야합니까? 내가 갔던 비주얼 스튜디오 2005
- 8. 높은 수준의 SSE 플래그는 GCC/clang에서 낮은 SSE 플래그를 암시합니까?
- 9. SSE 및 하이퍼 스레딩
- 10. glibc 및 SSE 기능
- 11. SSE 액세스 위반
- 12. 두 그래픽 버퍼의 XOR #
- 13. AudioUnit 버퍼의 길이를 조정하십시오.
- 14. 순환 버퍼의 데이터를 실시간으로보기
- 15. read() 버퍼의 횡설수설?
- 16. Z- 버퍼의 효율적인 구현
- 17. goback 명령어?
- 18. 동시에 여러 SIMD 명령어 세트를 사용할 때의 이점
- 19. 의 OpenMP와 SSE, 내 프로그램은
- 20. SSE 정규화가 간단한 근사보다 느린가요?
- 21. sse 유형의 배열 : 분할 오류
- 22. SSE (1,2,3,4) 최적화는 어떻게 사용합니까?
- 23. VC++ SSE 본질 최적화 이상한
- 24. C는 - GCC SSE 벡터 확장
- 25. CMake에서 sse 가용성을 감지하는 방법
- 26. Visual Studio 2008에서 SSE3/SSE4.1 명령어 세트를 활성화하려면 어떻게합니까?
- 27. 프로토콜 버퍼의 ASCII 안전 직렬화
- 28. 버퍼의 변화를 추적하기위한 보조 모드
- 29. J2ME에서 버퍼로 회전 버퍼의 대안?
- 30. 컴파일 할 때 amd_3dnow 명령어 세트를 제외하는 방법 openssl
나는 내가 10 번처럼 이것을 upvote 수 있으면 좋겠 :) –