我有一个来自 Github 的 Spir-V 解析器,它能够处理和修改 Spir-V 二进制文件。目前,我只想打印出
OpConstant
变量的字面值。
不幸的是,它没有打印出正确的值。
为了测试该应用程序,我将一个非常简单的 glsl 着色器转换为 Spir-V,然后使用下面的代码。
我的问题是我无法打印出
OpConstant
的字面值。它应该是常数的第四个词。 operands
指针应该表示第二个单词,所以这就是为什么我在写出字面值时添加+2。您可以在下图中看到OpConstant
的结构。
18.0f
。我还尝试进一步移动指针,因此在指针指向的地址上添加+1。
着色器是这样的:
#version 450
float value = 18.0f;
void main() {
}
这是完整的解析器代码。只需一个cpp:
#include <stdint.h>
#include <stdlib.h>
#include <string>
#include <direct.h> // _getcwd
#include <stdio.h> // printf
#include <string.h> // strlen
#include <iostream>
#include <stddef.h>
#include <stdio.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
static inline uint32_t bswap_32(uint32_t x) {
return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >> 8) |
((x & 0x0000ff00) << 8) | ((x & 0x000000ff) << 24);
}
#endif
struct sv_instr {
uint16_t word_count;
uint16_t opcode;
uint32_t* operands;
};
struct sv_module {
uint32_t magic;
uint32_t version;
uint32_t generator;
uint32_t bound;
uint32_t reserved;
struct sv_instr* instrs;
int num_instrs;
};
#define SV_MAGIC 0x07230203
#define SV_MAGIC_REV 0x03022307
int sv_read_instr(struct sv_instr* dst, uint32_t** words, int* num_words) {
if (*num_words < 1)
return -1;
dst->word_count = **words >> 16;
dst->opcode = **words & 0xFFFF;
/*
* WordCount needs to be at least 1, to encode the WordCount and
* Opcode itself
*/
if (dst->word_count < 1)
return -1; /* malformed instruction */
if (dst->word_count > *num_words)
return -1; /* not enough data */
dst->operands = *words+1;
*words += dst->word_count;
*num_words -= dst->word_count;
return 0;
}
int sv_read(struct sv_module* dst, uint32_t* words, int num_words) {
/* check if we have enough data to read header */
if (num_words < 5)
return -1;
dst->magic = *words++;
dst->version = *words++;
dst->generator = *words++;
dst->bound = *words++;
dst->reserved = *words++;
/* verify header-data */
if (dst->magic != SV_MAGIC)
return -1;
num_words -= 5;
dst->instrs = NULL;
dst->num_instrs = 0;
while (num_words > 0) {
struct sv_instr instr;
if (sv_read_instr(&instr, &words, &num_words) < 0)
return -1;
dst->instrs = (sv_instr*)realloc(dst->instrs, (dst->num_instrs + 1) * sizeof(instr));
if (!dst->instrs)
return -1;
dst->instrs[dst->num_instrs++] = instr;
}
return 0;
}
int main() {
const char* filename = "x64\\Debug\\shader.vert.spv";
FILE* file = NULL;
errno_t err = fopen_s(&file, filename, "rb");
if (err != 0) {
perror("fopen_s");
return 1;
}
struct sv_module mod;
uint32_t word, * words = NULL;
int num_words = 0, i;
while (fread(&word, 4, 1, file) == 1) {
words = (uint32_t*)realloc(words, (num_words + 1) * 4);
if (!words) {
perror("realloc");
fclose(file);
abort();
}
words[num_words++] = word;
}
fclose(file);
/* byte-swap input if needed */
if (num_words > 0 && words[0] == SV_MAGIC_REV)
for (i = 0; i < num_words; ++i)
words[i] = bswap_32(words[i]);
printf("words: %d\n", num_words);
if (sv_read(&mod, words, num_words) < 0) {
fprintf(stderr, "failed to read SPIR-V module\n");
return 1;
}
for (i = 0; i < mod.num_instrs; ++i) {
if (mod.instrs[i].opcode == 43) { // getting the OpConstant
// printing out the literal value
std::cout << *(mod.instrs[i].operands+2) << std::endl;
}
}
return 0;
}
代码很好,但是如果您想获取 OpConstant 的字面值,请使用
*reinterpret_cast<>()
来检索它,如下所示:
std::cout << *reinterpret_cast<float*>(mod.instrs[i].operands+2) << std::endl;