I am working on an iOS app which links several static libraries. The challenge is, those linked libraries define same method names with different implementations. Oddly, I don't get any duplicate symbol definition errors; but, to no surprise, I end up with access to only one implementation of the method.
To be more clear, say I have libA and libB and they both define a global C method called func1()
When I link both libA and libB, and make a call to func1(), it resolves to either libA's or libB's implementation without any compilation warning. I, however, need to be able to access both libA's func1() and libB's func1() separately.
There's a similar SO post that explains how it can be done in C (via symbol renaming) but unfortunately, as I found out, objcopy tool doesn't work for ARM architecture (hence iPhone).
(I will submit it to the App Store, hence, dynamic linking is not an option)
It appears that you are in luck - you can still rename symbols with the ARM binary format, it's just a bit more hacky than the objcopy method...
NOTE: This has only been tested minimally, and I would strongly advise you to make a backup of all libraries in question before trying this!
Also note that this only works for files not compiled with the C++ compiler! This will fail if the C++ compiler was used on these files.
First, you will need a decent hex editor, for this example, I will be using Hex Fiend.
Next, you will open up a copy of your of of your libraries, let's call it lib1-renamed.a, and do the following with it:
Find the name of the symbol you wish to re-name. It can be found using the nm tool, or, if you know the header name, you should be set.
Next, you will use hex fiend, and to a textual replace of the old name (in this case foo), and give it a new name (in this case, bar). These names must have the same length, or it will corrupt the binary's offsets!
Note: if there is more than one function that contain's foo's name in it, you may have problems.
Now, you must edit the headers of the library you changed, to use the new function name (bar) instead of the old one.
If you have done the three simple† steps above properly, you should now be able to compile & link the two files successfully, and call both implementations.
If you are trying to do this with a universal binary (e.g. one the works on the simulator as well), you'd be best off using lipo to separate the two binaries, using objcopy on the i386/x64 binary, and then using my method on the ARM binary, and lipo it back together.
†: Simplicity is not guaranteed, nor is it covered by the Richard J. Ross III super warranty. For more information about the super warranty, call 1-800-FREE-WARRANTY now. That's 1-800-FREE-WARRANTY now!
Related
I've tried searching through existing answers, but didn't find anything that helps with this exact situation, so here goes ...
I'm working on a project with a deliverable .so file that contains a lot of proprietary IP, so we want to tightly control the export symbols that it exposes. Examining the .so with the nm and objdump tools actually shows no symbols exposed (which seems a bit odd, as a client app is able to link with it), but opening it with Ghidra shows absolutely everything imaginable in the 'Exports' tree.
The project is C/C++ code being built in Visual Studio 2019, using the Clang 5.0 toolset (release build for ARM64, android-27). Perhaps important to note that the library exposes a C API, so none of the functions/structs/enums intended to be exposed are namespaced. The -fvisibility=hidden switch is being set, which I understand should hide symbols by default, and __attribute__((visibility("default"))) is being specified only on the functions we want to expose. But it doesn't appear to be working as expected.
As a sanity-check experiment, I hacked the code to change the __attribute__((visibility("default"))) to __attribute__((visibility("hidden"))), just to see what effect that would have, and was pleasantly relieved to see that the relevant functions no longer appeared in the Ghidra view. This suggests that we could use that to hide things we don't want exposed, but:
It's just not really feasible to go through the entire codebase to retrofit that everywhere.
Surely that shouldn't be necessary because the -fvisibility=hidden switch should be doing that as the default for everything in the library.
For comparison, there is a Windows DLL build of the same project, which declares __declspec(dllexport) in the relevant places (usual approach of using a macro to handle the various different build scenarios), and when examining the DLL in Ghidra, only the relevant functions that we want exposed are visible as being exported.
I just want the .so build to do the same thing, but can't seem to make it happen.
As a last-ditch effort, I tried using the llvm-strip tool to try removing symbols from the .so file after building, but to no avail (probably because the other tools didn't actually list any symbols in the first place).
Any advice would be gratefully received!
I am trying to get some a medium-to-large sized code base that is, frankly, well written with a high degree of portability.
I decided to package it as a loadable bundle (plugin) and piggy-backed off of one of the template app projects and followed some tutorials about adding a target for loadable bundles within an app.
Also, this loadable bundle depends on a custom framework which I built for iOS and added it as a dependent for the loadable bundle. ie. The plugin links to a framework wrapper for a static lib.
The custom framework built successfully. Granted I have not yet verified that it works. The idea is to test the integrated functionality.
My build settings are largely defaults with the exception of some preprocessor defines.
Because I don't really understand the code base yet, I am literally adding one file-at-a-time to the plugin target and building cleanly every 3-4 files added.
The build completes successfully but with many, many warnings as follows, with paths to intermediate build results...etc.:
"file was built for unsupported file format with a series of hex characters () which is not the architecture being linked (armv7s)". When I converted the hex chars to ascii it just showed "#1 /Users/my-username/? ".
When I do a 'file' on any .o in the intermediate build results, I get "ASCII c program text, with very long lines"
What am I doing wrong? What does that mean?
Thank you so much for your time.
The short answer is this:
If you get this message, then your project settings are messed up.
If you are linking your app against custom frameworks, make sure they are built as fat binaries
You will need to know very clearly the meanings of active architecture and how it is used and whether or not you want to only build the active architecture for your app, or all of the possible architectures.
If you are, like me, inheriting a slew of portable code that depended heavily on gcc and its extensions, expect to make changes around builtin* attributes and to make heavy use of __clang to make available macros that used to be defined through the GNUC et al.
Also, you will need to use the -E for clang to debug/understand the preprocessing and the file inclusion. That said, don't forget to take it out because effectively what will happen is that your .o will just contain text and the build may succeed, but the linker will give you the odd message subject of this question.
Finally, do understand that Xcode, like any piece of complex software, is buggy. Sometimes, it will keep settings that you get rid off. In my case, I included custom frameworks which I built after placing them in a local dir. Then I deleted them from the project and opted to trash when prompted. The build kept failing because the linker for some reason was looking for the local directory. You would have to edit the *.pbxproj and manually remove them.
I'm developing an iOS SDK that integrates other SDKs (Facebook SDK 3.5, for example).
To prevent collisions and allow my customers to import those SDKs as well, I want to rename all of the classes/enums in my code (for example, rename FBSession to RDFBSession, etc).
Is there an easy way to do this instead of going class-by-class and using Xcode's rename feature?
Apple provide a command-line tool called tops(1) that is designed for scripting large-scale code refactoring (renaming C functions, Objective-C methods, classes, and other tokens):
tops -verbose replace "FBSession" with "RDFBSession" Sources/*.[hm]
If you have a lot of replacements, you can put all of the replace... commands into a file that you pass with the -scriptfile option. The man page has more information on the more complex commands/options (and examples).
Xcode also offers textual Search and Replace. This will be faster than individual refactors, but it is ultimately less automated. You can make the step by step refactoring faster by first minimizing the project to the relevant dependencies/sources (if possible).
However, renaming the declarations in a library will not alter the symbol names of its associated binary. If it is distributed with a binary, then renaming will just result in linker errors or (in some cases) runtime errors.
The best idea if you need to use a 3rd party library which your clients might also use is to simply inform them they need to link the library with their app, then publish the version(s) the current release supports so they know they have some extra testing if they go too far ahead with some libraries.
I think that a better approach than simply renaming your classes would be to download Facebook's open source code, rename the classes there and compile a new static library with a set of renamed header files. Then you can be sure that no collisions occur and that you're using symbols that you named yourself.
I must warn you though - working like this may make updating the SDK a nightmare regardless of how you tackle this specific issue.
Beyond allowing one file to use another file's attributes, what actually happens behind the scenes? Does it just provide the location to access to that file when its contents are later needed, or does it load the implementation's data into memory?
In short;
The header file defines the API for a module. It's a contract listing which methods a third party can call. The module can be considered a black box to third parties.
The implementation implements the module. It is the inside of the black box. As a developer of a module you have to write this, but as a user of a third party module you shouldn't need to know anything about the implementation. The header should contain all the information you need.
Some parts of a header file could be auto generated - the method declarations. This would require you to annotate the implementation as there are likely to be private methods in the implementation which don't form part of the API and don't belong in the header.
Header files sometimes have other information in them; type definitions, constant definitions etc. These belong in the header file, and not in the implementation.
The main reason for a header is to be able to #include it in some other file, so you can use the functions in one file from that other file. The header includes (only) enough to be able to use the functions, not the functions themselves, so (we hope) compiling it is considerably faster.
Maintaining the two separately most results from nobody ever having written an editor that automates the process very well. There's not really a lot of reason they couldn't do so, and a few have even tried to -- but the editors that have done so have never done very well in the market, and the more mainstream editors haven't adopted it.
Well i will try:
Header files are only needed in the preprocessing phase. Once the preprocessor is done with them the compiler never even sees them. Obviously, the target system doesn't need them either for execution (the same way .c files aren't needed).
Instead libraries are executed during the linking phase.If a program is dynamically linked and the target environment doesn't have the necessary libraries, in the right places, with the right versions it won't run.
In C nothing like that is needed since once you compile it you get native code. The header files are copy pasted when u #include it . It is very different from the byte-code you get from java. There's no need for an interpreter(like the JVM): you just feed it your binary stuff to the CPU and it does its thing.
If you're building a commercial iOS SDK that will be included in other people's code and you have third party libraries that you have a license to, is there an effective way to simplify the library / framework structure by not exporting those 3rd party symbols in a static lib?
I appreciate I could instruct developers to check for overlapping symbols, but I'd like to minimize instructions. Ie, just want them to drop the lib into their project and off they go. I also do not want to export my third party symbols as they may change in later projects.
Unfortunately, there isn't a lot to be done here very easily. A static library is just a bunch of .o files glued together. There is no linker step to determine what pieces are actually needed between .o's. That's not done until the final link step (by your customer).
That said, there are some things you can think about:
First, whenever possible, avoid including sub-libraries inside of a static library. This is really dangerous if it's possible for the customer to have other copies of the same sub-library. Your situation seems to be difference since your sub-library is licensed, so the customer is unlikely to have multiple copies, but for example, you should never include a static copy of libcurl in your static library. You must ask the customer to link libcurl themselves, or else things will explode quite badly for them. (See Linking static libraries, that share another static library.) Again, this sounds like it may not apply to you, but keep it in mind if you have common open-source libraries in the mix.
An old-school solution for dealing with visibility is to glue together your compile units. This is a fancy way of saying "concatenate all your .c/.m files into one massive file and compile that." Any function you mark "static" will not be visible outside this compile unit, and so shouldn't be exported. This also happens to increase the possibility of compiler inlining and other optimizations (particularly without fancy link-time optimization) inside of your library.
See Symbol Exporting Strategies. You have several options:
marking symbols as static (probably not possible in this case since they come from a 3rd party)
Use an exported symbols list or an unexported symbols list
Set the visibility attribute of the symbol directly (again, probably not possible in this case)
Use -fvisibility command line option when compiling (probably your best bet here)
Use weak imports
Use a weak library
These are explained at the link above.