Can't link to .so file on Mac with CMake - macos

I'm working on a PHP 7 extension using Swig and am trying to link to libphp7.so. From my CMakeLists.txt file:
find_library(php7_lib php7 PATHS "/usr/local/Cellar/php/7.3.0/lib/httpd/modules" NO_DEFAULT_PATH)
target_link_libraries(navdb_php7_client_api ${php7_lib} dl)
But I get an error:
[100%] Linking CXX shared module .../lib/libnavdb_php7_client_api.so
...
ld: can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB) file '/usr/local/Cellar/php/7.3.0/lib/httpd/modules/libphp7.so' for architecture x86_64
The file I'm trying to link to:
$ file /usr/local/Cellar/php/7.3.0/lib/httpd/modules/libphp7.so
/usr/local/Cellar/php/7.3.0/lib/httpd/modules/libphp7.so: Mach-O 64-bit bundle x86_64
Any ideas on how to resolve this?

Although Apple recommends bundles be given the extension .bundle many developers give them the .so extension for the sake of cross-platform familiarity. On Linux, no distinction is made between a shared module (a bundle on MacOS) and a shared library (a dylib on MacOS.)
Understanding that, as ld states, you cannot link to an MH_BUNDLE on MacOS. It either needs to be a dylib to link it, or you need to load the .so using the dyld APIs.
This link gives an example of how to dynamically load a bundle on MacOS:
#include <stdio.h>
#import <mach-o/dyld.h>
int main( )
{
int the_answer;
int rc; // Success or failure result value
NSObjectFileImage img; // Represents the bundle's object file
NSModule handle; // Handle to the loaded bundle
NSSymbol sym; // Represents a symbol in the bundle
int (*get_answer) (void); // Function pointer for get_answer
/* Get an object file for the bundle. */
rc = NSCreateObjectFileImageFromFile("libanswer.bundle", &img);
if (rc != NSObjectFileImageSuccess) {
fprintf(stderr, "Could not load libanswer.bundle.\n");
exit(-1);
}
/* Get a handle for the bundle. */
handle = NSLinkModule(img, "libanswer.bundle", FALSE);
/* Look up the get_answer function. */
sym = NSLookupSymbolInModule(handle, "_get_answer");
if (sym == NULL)
{
fprintf(stderr, "Could not find symbol: _get_answer.\n");
exit(-2);
}
/* Get the address of the function. */
get_answer = NSAddressOfSymbol(sym);
/* Invoke the function and display the answer. */
the_answer = get_answer( );
printf("The answer is... %d\n", the_answer);
fprintf(stderr, "%d??!!\n", the_answer);
return 0;
}

I found out how/what to do from this link:
Clang and undefined symbols when building a library
The libphp7.so doesn't need to be linked to at compile time, run-time works fine. This can be enabled by setting a CXX_FLAG (see the link for details).

Related

Static library linking error "requires unsupported dynamic reloc"

I built Tensorflow using the scripts provided in contrib/makefile of the TF repo. As far as I can tell from the terminal output the generated libtensorflow-core.a should have been compiled with -fPIC enabled.
Now when I try to link that library into the shared library of an Android NDK project with
add_library(lib_tf STATIC IMPORTED )
set_target_properties(lib_tf PROPERTIES IMPORTED_LOCATION ${TF_BUILD}/libtensorflow-core.a)
add_library(native-lib SHARED ${SRC})
target_link_libraries(native-lib lib_tf)
it complains with
libtensorflow-core.a(config.pb.o): requires unsupported dynamic reloc R_ARM_REL32; recompile with -fPIC
This is the output of objdump
$ objdump -r libtensorflow-core.a
libtensorflow-core.a(test_log.pb.o): file format ELF32-arm-little
RELOCATION RECORDS FOR [.rel.text]:
0000075c R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite24WriteMessageMaybeToArrayEiRKNS0_11MessageLiteEPNS0_2io17CodedOutputStreamE
000009b8 R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite10WriteInt64EixPNS0_2io17CodedOutputStreamE
000009cc R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite10WriteInt64EixPNS0_2io17CodedOutputStreamE
00000a1c R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite16VerifyUtf8StringEPKciNS2_9OperationES4_
00000a34 R_ARM_CALL _ZN6google8protobuf8internal14WireFormatLite11WriteStringEiRKSsPNS0_2io17CodedOutputStreamE
00000a44 R_ARM_REL32 .LC3
...
So it seems it was compiled with -fPIC. I'm not sure what the problem is.
UPDATE:
I compiled it manually via the Android NDK arm toolchain and it worked. I don' know what Android Studio does differently.
my c++ toolchain gave me the same error today when I was trying
to link an object into a shared library for android. The error went away
when I fixed the namespace resolution I was using for an extern variable in the problem source file.
namespace {
namespace android {
extern int* sys_id ;
}
}
void home::fileList::report () {
// do stuff
initialize (android::sys_id) ;
// do stuff
}
above instigates "requires unsupported dynamic reloc" error, below succeeds
namespace m1 {
namespace android {
extern int* sys_id ;
}
}
void home::fileList::report () {
// do stuff
initialize (m1::android::sys_id) ;
// do stuff
}

Xcode Audiocomponent Symbols not found and somehow cant use methods

im new to coding in c++, I only programmed in php and Java but I want to learn something more.
It may be not the best to start with Audio things but I already know how programming works.
But, I thought to test, get a bit of code from the Apple website and look what happens.
I pasted the beginning of the Code in my Project and got errors. And I dont really know what they mean and searching didnt give me any results.
Thats the code:
#include <iostream>
#include <CoreAudio/CoreAudio.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
int main(int argc, const char * argv[]) {
// insert code here...
AudioComponent comp;
AudioComponentDescription desc;
AudioComponentInstance auHAL;
//There are several different types of Audio Units.
//Some audio units serve as Outputs, Mixers, or DSP
//units. See AUComponent.h for listing
desc.componentType = kAudioUnitType_Output;
//Every Component has a subType, which will give a clearer picture
//of what this components function will be.
desc.componentSubType = kAudioUnitSubType_HALOutput;
//all Audio Units in AUComponent.h must use
//"kAudioUnitManufacturer_Apple" as the Manufacturer
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
//Finds a component that meets the desc spec's
comp = AudioComponentFindNext(NULL, & desc);
if (comp == NULL) exit(-1);
//gains access to the services provided by the component
AudioComponentInstanceNew(comp, & auHAL);
return 0;
}
and those are the errors i get:
Undefined symbols for architecture x86_64:
"_AudioComponentFindNext", referenced from:
_main in main.o
"_AudioComponentInstanceNew", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
thanks for helping me out!
You'll need to add the AudioUnit, CoreAudio and AudioToolbox frameworks to your project. See this answer for help on how to do that.
You are definitely jumping in the deep end if this is your first experience with C++. Good luck!

Changing function reference in Mac OS Process at runtime

I need to change reference of a function in a Mac OS process at runtime to a custom function defined in my own custom dylib. I kept the new function signature same as the original.
For example I need to change "open" function to "myopen" function.
I tried processing __LINKEDIT segment to get the dynamic symbol table and string table.
I used following pointers,
1. the VMAddrress from __LINKEDIT segment,
2. mach_header and vmaddr_slide from the "_dyld_register_func_for_add_image" callback,
3. symoff and stroff from symtab_command.
But I am unable to get the symbol table and string table mentioned in the __LINKEDIT segment.
Can someone throw some light on this?
Thanks in advance.
If the function in question is a library function, and not statically compiled into the executable, you don't need to do any of that - you can use function interposing, instead. Specifically, add this to your library:
// The attribute creates a Mach-O Section in your library - q.v. libgmalloc.dylib for
// a nice example
static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_open, (void *)open },
{ (void *)my_close, (void *)close }, // .. etc
};
int my_open(const char *path, int flags, mode_t mode)
{
int rc;
// Prolog - do something before open
rc = open(path, flags, mode); // call real open
// Epilog - record rc, etc..
return rc;
}
There are several excellent books on OS X internals which can provide you with samples, though apparently according to S.O site policies we can't link you to them. That said, the above code snippet should work. Bear in mind, that this won't work on calls to open performed by other dylibs (though there are more complicated ways to get that, as well)

Why can't I create a MacOS framework with unresolved symbols?

I thought one feature of dynamic libraries (and by extension Apple's Mach-O Frameworks) was to leave some symbols (methods) undefined until the using application gets linked, but it appears all symbols have to be resolved for clang++ to successfully build a Framework.
For example, in building a framework for flight simulations, one might leave a C routine named aero undefined (but with an 'extern aero()' specification.) But XCode 4.2 refuses to build the framework, calling _aero an "undefined symbol."
Here's the header file included by both Objective-C and ANSI-C routines:
// FlightVehicleCAdapter_data.h
#ifndef FlightVehicleCAdapter_data_h
#define FlightVehicleCAdapter_data_h
#ifdef __cplusplus
external "C" {
#endif
extern void aero( void );
#ifdef __cplusplus
}
#endif
And here is where it gets called:
// FlightVehicleCAdapter.m
-(void) calcAero {
aero();
[self setBodyAeroForce_lb: [lsVector3 vectorFromScalarX:fv_data->f_aero_v.x
Y:fv_data->f_aero_v.y
Z:fv_data->f_aero_v.z]];
[self setBodyAeroMoment_ftlb:[lsVector3 vectorFromScalarX:fv_data->m_aero_v.x
Y:fv_data->m_aero_v.y
Z:fv_data->m_aero_v.z]];
}
I had hoped to be able to define the real aero() routine in the application that would link this framework, but when trying to build the framework itself the linker refuses to build it without a concrete aero() implementation:
Undefined symbols for architecture [i386|x86_64]:
"_aero", referenced from:
-[FlightVehicleCAdapter calcAero] in FlightVehicleCAdapter.o
So I then defined a dummy aero() routine:
// dummy_aero.c
// not showing fv_data structure definition for clarity
void aero(void){
fv_data->f_aero_v.x = 0.0;
fv_data->f_aero_v.y = 0.0;
fv_data->f_aero_v.z = 0.0;
fv_data->m_aero_v.x = 0.0;
fv_data->m_aero_v.y = 0.0;
fv_data->m_aero_v.z = 0.0;
}
This definition of aero() satisfies clang++ such that the Mach-O framework (dynamic library) is successfully built. But when I link the resulting framework with the application target which includes a non-trivial aero() routine, the framework's dummy aero() is being called instead of the application's aero().
You need to pass the -bundle_loader <executable> option to the linker, although I'm not sure that works for frameworks. Alternatively, you can use -undefined dynamic_lookup.
You need to do this for aero():
#ifdef __cplusplus
extern "C" {
#endif
extern void aero( void );
#ifdef __cplusplus
}
#endif
This makes sure the function is declared in C++ to have a C-resolvable name. C++ builds names differently than C does.
Note that then aero() can be linked at runtime.

Load a Mac binary as a dynamic library

I am doing some reverse engineering with a binary executable without sources. On Windows what I can do is load an executable file (EXE) with LoadLibrary, just as it was a DLL file. If the loaded file is not relocatable I can simply relocate my loader code to "make space" for the other module. When I have the binary loaded, I can call it's functions (assuming I where where they are, of course), and do other stuff.
Is there some way to do the same or similar on Mac? I have a mach-o executable, and I'd like to load it as it was a dynamic library (DYLIB). Or is there some way to convert an executable into a DYLIB? What are the real differences between an executable and a DYLIB?
OK, so I did some experiments, and see this. File "bin1.c" contains:
#include <stdio.h>
int main() {
printf("I am bin1.\n");
return 0;
}
and "bin2.c" is:
#include <stdio.h>
#include <dlfcn.h>
int main() {
printf("I am bin2.\n");
void *l = dlopen("bin1", RTLD_NOW);
if (l == NULL) {
printf("dlopen failed: %s\n", dlerror());
return -1;
}
void *f = dlsym(l, "main");
if (f == NULL) {
printf("dlsym failed: %s\n", dlerror());
return -1;
}
int (*main)() = f;
main();
return 0;
}
On my Mac, all compiles fine and indeed loads the other executable as it was a loadable library, and I can call the main function in the other binary:
Johanka:Desktop newacc$ uname -a
Darwin Johanka.local 11.3.0 Darwin Kernel Version 11.3.0: Thu Jan 12 18:47:41 PST 2012; root:xnu-1699.24.23~1/RELEASE_X86_64 x86_64
Johanka:Desktop newacc$ gcc bin1.c -o bin1 && ./bin1
I am bin1.
Johanka:Desktop newacc$ gcc bin2.c -o bin2 && ./bin2
I am bin2.
I am bin1.
Not sure though, whether there are limitations on this and if this can be done with non-relocatable binaries. But this example show that at least in some cases, it's possible.

Resources