parsingbytecodeopcodespir-v

How to print out the literal value of a Spir-V OpConstant?


I am have a Spir-V parser from Github, which is capable of processing and modifying the Spir-V binary. At the moment, I just would like to print out the literal value of the OpConstant variables. Unfortunately, it doesn`t print out the proper value. To test the app, I converted a really simple glsl shader to Spir-V and then used the code below.

My problem is that I could not print out the literal value of the OpConstant. It should be the forth word of the constant. The operands pointer should mean the second word, so that is why I added +2, when writing out the literal value. You can see the structure of OpConstant in the picture below.

OpConstant word order However, it is not 18.0f as it is in the shader. I also tried moving the pointer further, so adding +1 to the address pointed by the pointer.

The shader was this:

#version 450
float value = 18.0f;

void main() {
}

And this is the full parser code. Just one 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;
}

Solution

  • The code was good, however if you would like to get the literal value of the OpConstant, then use a *reinterpret_cast<>() to retrieve it like below:

     std::cout << *reinterpret_cast<float*>(mod.instrs[i].operands+2) << std::endl;