Limiting the scope of global symbols from linked objects
Asked Answered
M

1

4

I have a C library in an archive file, clib.a. I've written a C++ wrapper for it, cpp.o, and would like to use this as a static library:

ar cTrvs cppwrap.a clib.a cpp.o

Code which links to this won't be able to use the stuff from clib.a directly unless the correct header is included. However, if someone coincidentally creates an appropriate prototype -- e.g. void myCoincidentallyNamedGlobalFunction() -- I'm concerned which definition of myCoincidentallyNamedGlobalFunction will apply.

Since the symbols from clib.a only need to be accessed in cpp.o, and not anything linked to cppwrap.a, is there a way to completely hide them so that there is no possible collision (so even including the clib header would fail)?

Mistook answered 15/5, 2014 at 12:57 Comment(7)
Is clib.o something you're building yourself, or a monolithic binary you're handed by someone else that you want to wrap?Russian
@Russian I'm building it, yes.Mistook
So you have a couple options then, I think. You can hide methods/variables you don't want to export in anonymous namespaces, which is probably the cleanest way, or you can manually strip -N or objcopy -N symbols you don't want exposed from your final distributed library.Russian
OK, this might be dumb, but could he put clib.o in its own library, scrub the names and then archive that into cppwrap.a ?Ethic
OK, maybe not totally dumb, as Jeff thinks the same thing. I though symbol stripping mostly applied to debugging though....Ethic
@Russian If so I don't see it (multiple questions). It could be phrased "How can I link cpp.o to clib.o in cppwrap.a without exporting the symbols in clib.o via cppwrap.a?" clib.o is actually an archive itself (clib.a), if that makes any difference (I've edited the question to this effect)Mistook
@Russian - you're right, this doesn't apply here. Removing.Kinakinabalu
R
3

You can manually remove unneeded symbols on the final combined library:

$ objcopy -N foo cppwrap.a (remove symbol)

Or, if you need the symbols but want to make sure that external users can't get to them:

$ objcopy -L bar cppwrap.a (localize symbol)

Or, if a symbol in clib.a must be visible by something in cpp.o but you don't want it to be used by anyone else:

$ objcopy -W baz cppwrap.a (weaken symbol)

In this case, collisions with symbols from other object files/libraries will defer to their usage, even though the symbol will still be visible. To obscure things further or to reduce chances of even a deferential collision, you can also use:

$ objcopy --redefine-sym old=new cppwrap.a

An anonymous namespace may help in some cases, but not if there's functionality that your wrapper needs but is trying to hide from external users.

Russian answered 15/5, 2014 at 13:36 Comment(8)
The namespace solution will of course make it impossible for the functions in cpp.o to call the functions in clib.o.Orthogenetic
objcopy returns "not stripping symbol 'baz' because it is named in a relocation". Unless I misunderstand your example, using a namespace is no good since A) the code compiled into clib.o is C code, B) I don't want to have to modify clib at all, I just want to blackbox it completely inside the archive.Mistook
Right, it wasn't clear to me at first whether she needed to simply obscure superfluous symbols or is trying to ensure that core functionality can only be accessed through the cpp.o symbol names.Russian
@goldilocks OK, I think I see where you are a bit better now. Try objcopy -L baz cppwrap.a to localize a symbol.Russian
Hmmph. objcopy -L baz sounds right to me but then says, whereX/whereX/clib.o: No such file or directory although ar -t cppwrap.a lists clib.o and whereX/clib.o is created-- maybe that is a separate dilemma to do with ar -T ? :\Mistook
OK, as kind of a hack you can try objcopy -W baz clib.a before you ar it together. This keeps the symbol global but flags it as "weak", such that colliding symbols in later links will override it by default.Russian
Works for me -- you should mention that in the answer (I was ignorant of objcopy until now, it seems the right approach in context). Thx.Mistook
Glad my solution works for you, but I'm not sure that it's really the cleanest possible. If you are building both clib.a and the wrappers, you might want to endeavor to actually build the individual .o components with their respective C++ wrapper symbols so that you can truly remove the C symbols, rather than obscure or weakening them.Russian

© 2022 - 2024 — McMap. All rights reserved.