Re-using 'dllexport' for non-Windows targets

For our SHAVE target I have re-used ‘attribute((dllexport))’ to allow me to create indirect address tables for symbols with this annotation.

However, with almost every release of LLVM and CLang my implementation is broken and I have to rework my implementation. For the most part, the existing ‘dllexport’ attribute does everything I require and makes more sense for me to pass it through CLang/LLVM until it reaches our back-end where it emits the IAT support rather than adding my own new attribute.

This got broken again with v3.8 and this time the controls are more strict on Windows supporting targets. I thought that before I go in an make another set of changes to re-enable this with our target, that I would ask first if there anybody has any advice or recommendation for how to “borrow” this attribute for non-Windows targets? The problem is principally CLang rather than LLVM, so I would like to find a good and future-proof way of adapting CLang to enable this attribute on my target.

Thanks in advance,

MartinO

Martin J. O’Riordan Email: Martin.ORiordan@movidius.com

Compiler Development Web: www.movidius.com

Movidius Ltd. Skype: moviMartinO

1st Floor, O’Connell Bridge House, d’Olier Street, Dublin 2, Ireland

Sorry for the top post, on a mobile device.

What exactly is broken with the attribute application?

Is the issue with using the __declspec spelling? If so, -fdeclspec should allow that to come through. I believe that we treat the attribute the same irrespective of the spelling.

For our SHAVE target I have re-used ‘__attribute__((dllexport))’ to allow me
to create indirect address tables for symbols with this annotation.

What file format do you use? ELF?

I can see the point of dllimport (telling the compiler something is
known to be external, even in a non -fPIC build), but how is dllexport
different from a default symbol?

Cheers,
Rafael

Hi Saleem,

It’s not really a big problem. In the past I have had to merge my changes with the ongoing CLang changes to allow the ‘attribute((dllexport))’ to be permitted on objects for the SHAVE target. My approach was a little bit cheeky because I just tweaked/hacked the source to allow it for SHAVE too and all went well. But the changes in v3.8 from v3.7 are more semantically constrained and tighter bound to Windows and this approach no longer works.

The error I get is simply (I’m not using ‘__declspec’ syntax, just the GCC attribute syntax):

error: unknown attribute ‘dllexport’ ignored [-Werror,-Wunknown-attributes]

And I can fix this easily enough.

But since the ‘dllexport’ semantics are mostly what I want, it seems like a better idea to reuse it if possible than to add my own ‘iatexport’ attribute that more or less does what ‘dllexport’ already does. So rather than going in and making another set of ad-hoc changes to re-enable it for our target, I thought I would ask cfe-dev first to see if there was a better strategy before I “fix” it again only to find that v3.9 breaks my ad-hoc solution again, and v3.10 sometime farther down the road.

In response to Rafael Espindola’s questions:

What file format do you use? ELF?

I can see the point of dllimport (telling the compiler something is known to be external, even in a non -fPIC build), but how is dllexport different from a default symbol?

Yes, our target produces ELF files ultimately, though the compiler does not have an integrated assembler.

What I do with the attribute at code-generation is mostly treat it as an ordinary symbol, but I supplement their definitions with a set of data structures that when linked creates an IAT or Indirect Address Table that can be inspected at run-time. This is useful because the code running on the SHAVE cores is usually managed by an executive running on the Sparc Leon cores, and the dynamic lookup makes the programming model a lot simpler. The additional semantic checks and constraints that CLang places on ‘dllexport’ are also very valuable, as they make many incompatible or ill-advised use-cases become compile-time errors and warnings.

In summary, the CLang front-end semantics are very appropriate to my requirements, and my LLVM back-end emits normal symbols, but supplemented with the auxiliary IAT data structures.

It would be neat if I could “borrow” the existing ‘dllexport’ implementation for the most part, but in a structured well defined manner. I have had this working since LLVM v3.3, but each time I update to a new version I have to rework my adaptations, and going forward it would be good to have this better integrated using CLang best-practices rather than the ad-hoc I have used to date.

Thanks,

MartinO

What I do with the attribute at code-generation is mostly treat it as an
ordinary symbol, but I supplement their definitions with a set of data
structures that when linked creates an IAT or Indirect Address Table that
can be inspected at run-time. This is useful because the code running on
the SHAVE cores is usually managed by an executive running on the Sparc Leon
cores, and the dynamic lookup makes the programming model a lot simpler.
The additional semantic checks and constraints that CLang places on
‘dllexport’ are also very valuable, as they make many incompatible or
ill-advised use-cases become compile-time errors and warnings.

In summary, the CLang front-end semantics are very appropriate to my
requirements, and my LLVM back-end emits normal symbols, but supplemented
with the auxiliary IAT data structures.

It would be neat if I could “borrow” the existing ‘dllexport’ implementation
for the most part, but in a structured well defined manner. I have had this
working since LLVM v3.3, but each time I update to a new version I have to
rework my adaptations, and going forward it would be good to have this
better integrated using CLang best-practices rather than the ad-hoc I have
used to date.

OK, so the difference is just in clang?

An ELF symbol with default visibility is preemptable already. The IAT
you describe sounds a lot like the got that is used for preemption in
other architectures.

Cheers,
Rafael

It should just work if you remove the Windows-only restriction in Attr.td:

def DLLExport : InheritableAttr, TargetSpecificAttr {
let Spellings = [Declspec<“dllexport”>, GCC<“dllexport”>];
let Subjects = SubjectList<[Function, Var, CXXRecord]>;
let Documentation = [Undocumented];
}

def DLLImport : InheritableAttr, TargetSpecificAttr {
let Spellings = [Declspec<“dllimport”>, GCC<“dllimport”>];
let Subjects = SubjectList<[Function, Var, CXXRecord]>;
let Documentation = [Undocumented];
}

I know Sony does this, so it can’t require too much patching.

I know Sony does this, so it can’t require too much patching.

Heh. It’s one of the bigger lumps of our local changes.

Yes we support dllexport/dllimport for PS4 target (ELF). I remember there are both Clang and LLVM parts to the implementation, although I don’t have the details off the top of my head, and Warren has volunteered to move it all upstream. Somehow it keeps being interrupted by an imminent release, but I know he wants to get to it soon.

–paulr

Sorry for the delay responding. Yes, this is what I had done in the past, but removing this means that the attribute is enabled for all targets. We build clang/llvm for the SHAVE target, plus the X86 and Sparc. The X86 is useful to verify that we haven’t broken anything with our changes for SHAVE, and the Sparc target is simply an experiment to see what code generation looks like for our Leon cores compared to the GCC code generation which we use for our Sparc Leon cores.

Of course, it is not really a problem allowing ‘dllexport’ on other platforms, I think it will get ignored in the back-ends anyway; but I was really wondering if there was a more elegant approach.

One technique I think might work is to replace:

def DLLExport : InheritableAttr, TargetSpecificAttr {

with:

def DLLExport : InheritableAttr, TargetSpecificAttr {

and then making the predicate ‘EnableDllExport’ be ‘TargetWindows’ OR ‘TargetSHAVE’; thus enabling it only where it is intended.

Thanks again,

MartinO

Yes it is similar to, though not identical to GOT. Also because we have a non-gas compliant assembler, there is no way of passing GOT information on to the ELF emission. Our compiler does not have an LLVM integrated assembler unfortunately - I'm not even sure I can build an integrated assembler for VLIW with LLVM.

Thanks,

  MartinO

Other than syntax in the .s, what is the difference from using a got?

Cheers,
Rafael