graphitemaster / incbin

Include binary files in C/C++
The Unlicense
966 stars 90 forks source link

Not working in emscripten #37

Closed jpcima closed 2 years ago

jpcima commented 4 years ago

Hi, I've checked if this would work using the emscripten compiler. I try to compile the test program.

<inline asm>:1:17: error: Expected ,, instead got: 
.section .rodata
<inline asm>:16:6: error: symbol 'gLoremData': unsupported subtraction expression used in relocation.
.int gLoremEnd - gLoremData

I've no doubt the section statement can be fixed, by examing some -S output from the compiler. Regarding the second, I don't have any ideas.

graphitemaster commented 4 years ago

The second error is caused by the first error. When the first error occurs the actual label of the data doesn't end up in the rodata section it ends up in the default section, text and performing subtractions in the text section isn't allowed because text is relocated. I guess one needs to figure out why one cannot use rodata in emscripten?

graphitemaster commented 4 years ago

I'm surprised inline assembly works in emscripten at all too

jpcima commented 4 years ago

A working syntax for this assembly seems to be: .section .rodata.foo,"",@ I don't know yet about what these other arguments mean, it's an output of compiling a const array of char.

graphitemaster commented 4 years ago

That's a strange syntax. Is the .foo part necessary?

jpcima commented 4 years ago

I did some research of my own, and had some success, but the way to achieve it is a little more quirky. Emscripten 1.39.1, didn't try others.

  1. create empty program with one INCBIN

It fails with the following. fatal error: error in backend: data symbols must have a size set with .size: gHelloData

  1. create program with one INCBIN, printing all 3 variables

When any of the 3 variables is used in code, emcc will generate a .size directive for it, which makes disappear the previous error. It's needed to do it with all 3 to make it build successfully. (print them for instance)

When this is done, following -S output is obtained from the compiler. Note a curious 0 for gHelloData.

    .size   gHelloSize, 4
    .size   gHelloData, 0
    .size   gHelloEnd, 4
  1. manual definition of .size in asm source

I find I can introduce .size directives myself, and then source will build. It will still generate its own .size at the bottom like in the step 2, including gHelloData 0.

#if defined(__wasm64__)
    ".size gHelloEnd, 8\n"
#else
    ".size gHelloEnd, 4\n"
#endif
    ".size gHelloSize, 4\n"
    ".size gHelloData, gHelloEnd-gHelloData\n"

From what I can tell, this technique has worked, since I can run the program and get such output:

Example 2
Size: 14
Start: 0x400
End: 0xe0001
Hello, World!

4. Test

These are test files used, which serve to compare the method in 2. and 3. Hello1.c.gz Hello2.c.gz

That's a strange syntax. Is the .foo part necessary?

From what I can tell, it isn't. I found Assembler source to be located here, it only checks for the segment to begin with a ".rodata" string. https://github.com/llvm-mirror/llvm/blob/2c4ca6832fa6b306ee6a7010bfb80a3f2596f824/lib/MC/MCParser/WasmAsmParser.cpp#L119

graphitemaster commented 4 years ago

Having to know the size ahead of time isn't a workable solution. The point of the subtraction is to calculate the size with the assembler, not sure if this will work

district10 commented 4 years ago

I use __EMSCRIPTEN__ + --preload-file as a workaround.

graphitemaster commented 2 years ago

There's no solution for this as WASM does not support specifying unsized data and then computing the size later like we need.