> On Sep 28, 2017, at 5:23 PM, Saleem Abdulrasool <compn...@compnerd.org> wrote:
> 
> 
> 
> On Thu, Sep 28, 2017 at 10:59 AM, John McCall <rjmcc...@apple.com 
> <mailto:rjmcc...@apple.com>> wrote:
> 
>> On Sep 28, 2017, at 1:01 PM, Saleem Abdulrasool <compn...@compnerd.org 
>> <mailto: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.
> 
> I misunderstood your previous statement as saying that classes already used 
> absolute pointers for the nominal type metadata.  Just wanted to make sure 
> that I wasn't looking at the wrong area of the code.

Oh, sorry.  I actually thought they did and was just mistaken.

John.

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

Reply via email to