> On Sep 28, 2017, at 1:01 PM, Saleem Abdulrasool <compn...@compnerd.org> wrote:
> 
> On Mon, Sep 25, 2017 at 10:18 PM, John McCall <rjmcc...@apple.com 
> <mailto:rjmcc...@apple.com>> wrote:
>> On Sep 26, 2017, at 12:35 AM, Saleem Abdulrasool <compn...@compnerd.org 
>> <mailto:compn...@compnerd.org>> wrote:
>> On Mon, Sep 25, 2017 at 11:47 AM, John McCall <rjmcc...@apple.com 
>> <mailto:rjmcc...@apple.com>> wrote:
>> > On Sep 25, 2017, at 12:24 PM, Joe Groff <jgr...@apple.com 
>> > <mailto:jgr...@apple.com>> wrote:
>> >> On Sep 24, 2017, at 10:30 PM, John McCall <rjmcc...@apple.com 
>> >> <mailto:rjmcc...@apple.com>> wrote:
>> >>> On Sep 22, 2017, at 8:39 PM, Saleem Abdulrasool <compn...@compnerd.org 
>> >>> <mailto:compn...@compnerd.org>> wrote:
>> >>>
>> >>> On Thu, Sep 21, 2017 at 10:28 PM, John McCall <rjmcc...@apple.com 
>> >>> <mailto:rjmcc...@apple.com>> wrote:
>> >>>
>> >>>> On Sep 21, 2017, at 10:10 PM, Saleem Abdulrasool <compn...@compnerd.org 
>> >>>> <mailto:compn...@compnerd.org>> wrote:
>> >>>>
>> >>>> On Thu, Sep 21, 2017 at 5:18 PM, John McCall <rjmcc...@apple.com 
>> >>>> <mailto:rjmcc...@apple.com>> wrote:
>> >>>>> On Sep 21, 2017, at 1:26 PM, Saleem Abdulrasool via swift-dev 
>> >>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>> >>>>> On Thu, Sep 21, 2017 at 12:04 PM, Joe Groff <jgr...@apple.com 
>> >>>>> <mailto:jgr...@apple.com>> wrote:
>> >>>>>
>> >>>>>
>> >>>>>> On Sep 21, 2017, at 11:49 AM, Saleem Abdulrasool 
>> >>>>>> <compn...@compnerd.org <mailto:compn...@compnerd.org>> wrote:
>> >>>>>>
>> >>>>>> On Thu, Sep 21, 2017 at 10:53 AM, Joe Groff <jgr...@apple.com 
>> >>>>>> <mailto:jgr...@apple.com>> wrote:
>> >>>>>>
>> >>>>>>
>> >>>>>>> On Sep 21, 2017, at 9:32 AM, Saleem Abdulrasool via swift-dev 
>> >>>>>>> <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:
>> >>>>>>>
>> >>>>>>> Hello,
>> >>>>>>>
>> >>>>>>> The current layout for the swift metadata for structure types, as 
>> >>>>>>> emitted, seems to be unrepresentable in PE/COFF (at least for 
>> >>>>>>> x86_64).  There is a partial listing of the generated code following 
>> >>>>>>> the message for reference.
>> >>>>>>>
>> >>>>>>> When building the standard library, LLVM encounters a relocation 
>> >>>>>>> which cannot be represented.  Tracking down the relocation led to 
>> >>>>>>> the type metadata for SwiftNSOperatingSystemVersion.  The metadata 
>> >>>>>>> here is _T0SC30_SwiftNSOperatingSystemVersionVN.  At +32-bytes we 
>> >>>>>>> find the Kind (1).  So, this is a struct metadata type.  Thus at 
>> >>>>>>> Offset 1 (+40 bytes) we have the nominal type descriptor reference.  
>> >>>>>>> This is the relocation which we fail to represent correctly.  If I'm 
>> >>>>>>> not mistaken, it seems that the field is supposed to be a relative 
>> >>>>>>> offset to the nominal type descriptor.  However, currently, the 
>> >>>>>>> nominal type descriptor is emitted in a different section (.rodata) 
>> >>>>>>> as opposed to the type descriptor (.data).  This cross-section 
>> >>>>>>> relocation cannot be represented in the file format.
>> >>>>>>>
>> >>>>>>> My understanding is that the type metadata will be adjusted during 
>> >>>>>>> the load for the field offsets.  Furthermore, my guess is that the 
>> >>>>>>> relative offset is used to encode the location to avoid a relocation 
>> >>>>>>> for the load address base.  In the case of windows, the based 
>> >>>>>>> relocations are a given, and I'm not sure if there is a better 
>> >>>>>>> approach to be taken.  There are a couple of solutions which 
>> >>>>>>> immediately spring to mind: moving the nominal type descriptor into 
>> >>>>>>> the (RW) data segment and the other is to adjust the ABI to use an 
>> >>>>>>> absolute relocation which would be rebased.  Given that the type 
>> >>>>>>> metadata may be adjusted means that we cannot emit it into the RO 
>> >>>>>>> data segment.  Is there another solution that I am overlooking which 
>> >>>>>>> may be simpler or better?
>> >>>>>>
>> >>>>>> IIRC, this came up when someone was trying to port Swift to Windows 
>> >>>>>> on ARM as well, and they were able to conditionalize the code so that 
>> >>>>>> we used absolute pointers on Windows/ARM, and we may have to do the 
>> >>>>>> same on Windows in general. It may be somewhat more complicated on 
>> >>>>>> Win64 since we generally assume that relative references can be 
>> >>>>>> 32-bit, whereas an absolute reference will be 64-bit, so some formats 
>> >>>>>> may have to change layout to make this work too. I believe Windows' 
>> >>>>>> executable loader still ultimately maps the final PE image 
>> >>>>>> contiguously, so alternatively, you could conceivably build a Swift 
>> >>>>>> toolchain that used ELF or Mach-O or some other format with better 
>> >>>>>> support for PIC as the intermediate object format and still linked a 
>> >>>>>> final PE executable. Using relative references should still be a win 
>> >>>>>> on Windows both because of the size benefit of being 32-bit and the 
>> >>>>>> fact that they don't need to be slid when running under ASLR or when 
>> >>>>>> a DLL needs to be rebased.
>> >>>>>>
>> >>>>>>
>> >>>>>> Yeah, I tracked down the relativePointer thing.  There is a nice 
>> >>>>>> subtle little warning that it is not fully portable :-).  Would you 
>> >>>>>> happen to have a pointer to where the adjustment for the absolute 
>> >>>>>> pointers on WoA is?
>> >>>>>>
>> >>>>>> You are correct that the image should be contiugously mapped on 
>> >>>>>> Windows.  The idea of MachO as an intermediatary is rather 
>> >>>>>> intriguing.  Thinking longer term, maybe we want to use that as a 
>> >>>>>> global solution?  It would also provide a nicer autolinking mechanism 
>> >>>>>> for ELF which is the one target which currently is missing this 
>> >>>>>> functionality.  However, if Im not mistaken, this would require a 
>> >>>>>> MachO linker (and the only current viable MachO linker would be 
>> >>>>>> ld64).  The MachO binary would then need to be converted into ELF or 
>> >>>>>> COFF.  This seems like it could take a while to implement though, but 
>> >>>>>> would not really break ABI, so pushing that off to later may be wise.
>> >>>>>
>> >>>>> Intriguingly, LLVM does support `*-*-win32-macho` as a target triple 
>> >>>>> already, though I don't know what Mach-O to PE linker (if any) that's 
>> >>>>> intended to be used with. We implemented relative references using 
>> >>>>> current-position-relative offsets for Darwin and Linux both because 
>> >>>>> that still allows for a fairly convenient pointer-like C++ API for 
>> >>>>> working with relative offsets, and because the established toolchains 
>> >>>>> on those platforms already have to support PIC so had most of the 
>> >>>>> relocations we needed to make them work already; is there another base 
>> >>>>> we could use for relative offsets on Windows that would fit in the set 
>> >>>>> of relocations supported by standard COFF linkers?
>> >>>>>
>> >>>>>
>> >>>>> Yes, the `-windows-macho` target is used for UEFI :-).  The MachO 
>> >>>>> binary is translated later to PE/COFF as required by the UEFI 
>> >>>>> specification.
>> >>>>>
>> >>>>> There are only two relocation types which can be used for relative 
>> >>>>> displacements: __ImageBase relative (IMAGE_REL_*_ADDR32NB) and section 
>> >>>>> relative (IMAGE_REL_*_SECREL) which are relative to the beginning of 
>> >>>>> the section.  The latter is why I mentioned that moving them into the 
>> >>>>> same section could be a solution as that would allow the relative 
>> >>>>> distance to be encoded.  Unfortunately, the section relative 
>> >>>>> relocation is relative to the section within which the symbol is.
>> >>>>
>> >>>> What's wrong with IMAGE_REL_AMD64_REL32?  We'd have to adjust the 
>> >>>> relative-pointer logic to store an offset from the end of the relative 
>> >>>> pointer instead of the beginning, but it doesn't seem to have a section 
>> >>>> requirement.
>> >>>>
>> >>>> Hmm, is it possible to use RIP relative addressing in data?  If so, 
>> >>>> yes, that could work.
>> >>>
>> >>> There's no inherent reason, but I wouldn't put it past the linker to 
>> >>> fall over and die.  But it should at least be section-agnostic about the 
>> >>> target, since this is likely to be used for all sorts of PC-relative 
>> >>> addressing.
>> >>>
>> >>>
>> >>> At least MC doesnt seem to like it.  Something like this for example:
>> >>>
>> >>> ```
>> >>>  .data
>> >>> data:
>> >>>  .long 0
>> >>>
>> >>>  .section .rodata
>> >>> rodata:
>> >>>  .quad data(%rip)
>> >>> ```
>> >>>
>> >>> Bails out due to the unexpected modifier.  Now, theoretically, we could 
>> >>> support that modififer, but it does seem pretty odd.
>> >>>
>> >>> Now, as it so happens, both PE and PE+ have limitations on the file size 
>> >>> at 4GiB.  This means that we are guaranteed that the relative difference 
>> >>> is guaranteed to fit within 32-bits. This is where things get really 
>> >>> interesting!
>> >>>
>> >>> We cannot generate the relocation because we are emitting the values at 
>> >>> pointer width.  However, the value that we are emitting is a relative 
>> >>> offset, which we just determined to be limited to 32-bits in width.  The 
>> >>> thing is, the IMAGE_REL_AMD64_REL32 doesn't actually seem to care about 
>> >>> the cross-setionness as you pointed out.  So, rather than emitting a 
>> >>> pointer-width value (`.quad`), we could emit a pad (`.long 0`) and 
>> >>> follow that with the relative displacement (`.long <expr>`).  This would 
>> >>> be representable in the PE/COFF model.
>> >>>
>> >>> If I understand the layout correctly, the type metadata fields are 
>> >>> supposed to be pointer sized.  I assume that we would like to maintain 
>> >>> that across the formats.  It may be possible to alter the emission to 
>> >>> change the relative pointer emission to emit a pair of longs instead for 
>> >>> PE/COFF with a 64-bit pointer value.  Basically, we cannot truncate the 
>> >>> relocation to a IMAGE_REL_AMD64_REL32 but we could generate the 
>> >>> appropriate relocation and pad to the desired width.
>> >>>
>> >>> Are there any pitfalls that I should be aware of trying to adjust the 
>> >>> emission to do this?  The only downsides that I can see is that the  
>> >>> emission would need to be taret dependent (that is check the output 
>> >>> object format and the target pointer width).
>> >>>
>> >>> Thanks for the hint John!  It seems that was spot on :-).
>> >>
>> >> Honestly, I don't know that there's a great reason for this pointer to be 
>> >> relative in the first place.  The struct metadata will already have an 
>> >> absolute pointer to the value witness table which requires load-time 
>> >> relocation, so  maybe we should just make this an absolute pointer, too, 
>> >> unless we're seriously considering making that a relative pointer before 
>> >> allocation.
>> >>
>> >> In practice this will just be a rebase, not a full relocation, so it 
>> >> should be relatively cheap.
>> >
>> > At one point we discussed the possibility of also making the value witness 
>> > table pointer relative, which would allow concrete value type metadata to 
>> > be fully read-only, and since code invoking a value witness is almost 
>> > certainly going to have the base type metadata pointer live, probably not 
>> > an undue burden on code size.
>> 
>> Yes, that's true.  It would make the base of the load (metadata + 
>> loaded-offset + immediate-offset), which I think would require an extra 
>> instruction even on x86, but maybe that's not so bad.
>> 
>> On the other hand, yes, it would not be possible to refer to prebuilt 
>> vwtables from the runtime, and it would need to be a 64-bit relative offset 
>> in order to handle dynamic instantiation correctly, which as you say is 
>> problematic on some platforms.
>> 
>> Hmm, Im not sure I understand the desired approach.  Would we want to switch 
>> to a rebased pointer?
> 
> That's what we're discussing.  Switching to an absolute pointer (i.e. a 
> normal pointer, which would need to be rebased) has proven to be generally 
> more portable because many linkers do not support 64-bit relative pointers.  
> Also, since this is adjacent to another absolute pointer, the benefits of a 
> relative pointer seem pretty weak: it would eliminate a very small amount of 
> work at load time and (probably) some binary-size overhead, but that's 
> relatively minor compared to, say, whether the loader has to dirty any 
> memory.  Now, maybe we can avoid it being adjacent to another absolute 
> pointer by making the vwtable relative, and that would have some significant 
> upsides, but it would also have some significant drawbacks, and it's not 
> clear that anybody actually wants to put any time into that investigation 
> before we reach ABI stability.
> 
> I'm personally leaning towards saying that vwtables should just stay 
> absolute, and thus that nominal-type-descriptor pointers should just become 
> absolute to make things easier.  I'm not worried about the binary-size 
> impact; it's just a rebase, and Mach-O encodes rebases pretty efficiently.  
> It's a little unfortunate for ELF, which has wastefully large loader 
> encodings, but we could address that specifically if we felt the urge (or 
> maybe just do ELF infrastructure work on more efficient encodings).
> 
>> Would this be for all of the metadata or just the struct type?
> 
> Only structs, enums, and classes have nominal type metadata, and classes use 
> an absolute pointer.
> 
> I thought that I would take a stab at this since this is the penultimate 
> issue preventing the Windows x86_64 stdlib build.  Maybe I'm misreading 
> something, but the compiler seems to indicate that the class metadata has a 
> relative pointer?
> 
> template <class Impl>
> class ClassMetadataBuilderBase : public ClassMetadataVisitor<Impl> {
>   ...
>   void addNominalTypeDescriptor() {
>     auto descriptor = ClassNominalTypeDescriptorBuilder(IGM, Target).emit();
>     B.addFarRelativeAddress(descriptor);
>   }
>   ...
> }
>  
> The addFarRelativeAddress would handle this the same way as the other cases 
> AFAICT.

I'm not sure what you're getting at here.  The compiler is using a relative 
pointer because that's the current ABI.  Implementing a structural change in 
metadata emitted by the compiler and interpreted by the runtime will obviously 
require changing both the compiler and the runtime.

John.


>> Are there no other instances of the same pattern?
> 
> At the very least, none of the other instances have the 64-bit problem.  
> They're also just generally more likely to be internal to a section.
> 
> John.
> 
> 
>>  
>> 
>> John.
>> 
>> > It's a fair question though whether we'll ever get around to that 
>> > analysis, and I think the nominal type descriptor reference is the only 
>> > place we statically emit a pointer-sized rather than 32-bit relative 
>> > offset, which has caused problems for ports to other platforms that only 
>> > support 32-bit relative offsets.
>> 
>> 
>> >
>> > -Joe
>> 
>> 
>> 
>> 
>> -- 
>> Saleem Abdulrasool
>> compnerd (at) compnerd (dot) org
> 
> 
> 
> 
> -- 
> Saleem Abdulrasool
> compnerd (at) compnerd (dot) org

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to