This is an archive of the discontinued LLVM Phabricator instance.

[WebAssembly] Add new relocation for location relative data
ClosedPublic

Authored by kateinoigakukun on Feb 13 2021, 9:16 PM.

Details

Summary

This R_WASM_MEMORY_ADDR_SELFREL_I32 relocation represents an offset
between its relocating address and the symbol address. It's very similar
to R_X86_64_PC32 but restricted to be used for only data segments.

S + A - P

A: Represents the addend used to compute the value of the relocatable
field.
P: Represents the place of the storage unit being relocated.
S: Represents the value of the symbol whose index resides in the
relocation entry.

Proposal: https://github.com/WebAssembly/tool-conventions/issues/162

Diff Detail

Event Timeline

kateinoigakukun requested review of this revision.Feb 13 2021, 9:16 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 13 2021, 9:16 PM

Addressed clang-tidy warnings

Addressed clang-tidy warnings in lld

Is the "pc-rel" in the title a little misleading? How about just "relative" or "location relative"?

Thinking a little more about this, would it not make sense to have these relative relocations in the code section instead (or in addition)? I assume the idea is to do stuff like this:

i32.load <some_base_pointer>
i32.load <selfrel_location>
i32.add
.. use absolute pointer ..

In that case wouldn't it be better to just do:

i32.load <some_base_pointer>
i32.const <relative_relocation>
i32.add
.. use absolute pointer ..

This would save using memory at all and just embed the relative offset into the i32.const instruction.

llvm/test/MC/WebAssembly/selfrel.ll
48 ↗(On Diff #323600)

What happens today with this code? (without this change would this fail in some way?).

kateinoigakukun added a comment.EditedFeb 14 2021, 12:52 PM

@sbc100 Thanks for taking a look!

Is the "pc-rel" in the title a little misleading? How about just "relative" or "location relative"?

You are right. it seems "location relative" is suitable. I'll change naming in my patch also.

Thinking a little more about this, would it not make sense to have these relative relocations in the code section instead (or in addition)? I assume the idea is to do stuff like this:

i32.load <some_base_pointer>
i32.load <selfrel_location>
i32.add
.. use absolute pointer ..

In that case wouldn't it be better to just do:

i32.load <some_base_pointer>
i32.const <relative_relocation>
i32.add
.. use absolute pointer ..

This would save using memory at all and just embed the relative offset into the i32.const instruction.

In the latter case, the relocation needs to have two symbols to calculate the difference. On the other hand, the former case requires a single symbol to calculate the diff because it's relative to selfrel_location itself.

Do you think we can have two symbols in a reloc?

llvm/test/MC/WebAssembly/selfrel.ll
48 ↗(On Diff #323600)

What happens today with this code? (without this change would this fail in some way?).

llvm/test/MC/WebAssembly/selfrel.ll
48 ↗(On Diff #323600)

Yes, this kind of subtractions between cross-sections are failing now because the diff can not be fixed at compile-time layout.

kateinoigakukun retitled this revision from [WebAssembly] Add new relocation for pc-rel data to [WebAssembly] Add new relocation for location relative data.Feb 14 2021, 1:03 PM

Update naming from pc relative to location relative

This generally looks nice to me.. but my reservations on how useful this is beyond a singular use case still stand: https://github.com/WebAssembly/tool-conventions/issues/162

This generally looks nice to me.. but my reservations on how useful this is beyond a singular use case still stand: https://github.com/WebAssembly/tool-conventions/issues/162

I couldn't come up with another use case. But without this reloc type, every frontend compiler using relative-ptr needs to work around this issue, so I think adding a new reloc type is meaningful. (I know only a few compilers are using relative-ptr, but ...)
And also, in my investigation, using relative-ptr makes Swift's binary size about 5% smaller than absolute-ptr one. Binary size is one of the most sensitive aspects in wasm binary, so we want to use relative ptr on wasm64.

Ok, well, I am fine with this patch if @sbc100 is.

Mostly lgtm. Just a few nits at this point.

I don't love the name SELFREL but naming is hard and I'm not sure I can think of a better one. (LOCREL for location-relative?) Also, since can renaming the enum later without breaking compat we are not locked into the name. I wonder if we should rename of the existing REL relocation types to MBREL and TBREL to be explicit there too? (Not suggesting you do that as part of this change).

lld/test/wasm/selfrel-reloc.ll
27 ↗(On Diff #323630)

Can we write this test in assembly? I've been trying to convert all the lld test to asm so would rather not add more .ll tests here. Also I think it might be a lore more concise/readable perhaps in .s form?

lld/wasm/InputFiles.cpp
184

Is this correct? It looks like we are expecting the value written to the location to be the start of the segment containing the symbol? (Maybe this works because we default to -fdata-sections?)

llvm/test/MC/WebAssembly/selfrel.ll
1 ↗(On Diff #323630)

Can we give this test file a more descriptive name? How about reloc-relative.ll or reloc-selfrel.ll ? (to match the other tests in this directory that start with reloc-

Re-write lld test in assembly, fix expected provisioning value, and rename test file to match naming convention in the directory

lld/wasm/InputFiles.cpp
184

That was incorrect 😅 I fixed it and added tests to catch this bug. Thanks.

sbc100 added a comment.Mar 1 2021, 2:15 PM

I don't have any more objections myself. @sunfish , WDYT of this addition? My feeling is that if it helps swift then its probably worth adding.

lld/test/wasm/reloc-relative.s
4

Do you need --allow-undefined here?

30

How does this not trigger the can not be placed in a different section error in the object writer?

kateinoigakukun added inline comments.Mar 1 2021, 4:27 PM
lld/test/wasm/reloc-relative.s
4

Yes, hello.s requires puts symbol but this test doesn't use printing function, so I put --allow-undefined to ignore such unrelated symbols.

## hello.s

  .globl  hello
hello:
  .functype hello () -> ()
  i32.const hello_str
  call  puts
  end_function

  .section  .rodata.hello_str,"",@
  .globl  hello_str
hello_str:
  .asciz  "hello\n"
  .size hello_str, 7

  .functype puts (i32) -> ()
30
S + A - P

R_WASM_MEMORY_ADDR_LOCREL_I32 allows S to be a symbol in a different section, but doesn't allow P to be in a different section. This limitation is because a relocation entry can have only one symbol, so the base address (P) needs to be relative to the writing location.

In this case, hello_str is an external section symbol, but S can be a symbol in a different section and bar is placed in the same section with writing location, so does not trigger can not be placed in a different section.
This expression emits the below relocation entry.

Relocation {
  Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23)
  Offset: 0x0
  Symbol: hello_str
  Addend: 0
}
sbc100 accepted this revision.Mar 4 2021, 12:06 AM
This revision is now accepted and ready to land.Mar 4 2021, 12:06 AM

Resolved conflicts between main branch

@sbc100 Thanks for your approval! I don't have commit access, so could you land this patch? 🙏

Sorry for repeating 🙇 Could anyone land this patch to the main branch?

I can land it.. let me pull it in locally and run tests to be sure.

This revision was automatically updated to reflect the committed changes.

Thank you very much!