I've embedded some C# code into an iphone objective-c app using monotouch. I'm able to call into the C# code and get a return value, but I am not able to invoke a C function from the C# code using PInvoke. I am attempting to get a trivial example working. It is a simple calculator. The objective c code calls into the C# code to add two integers. The C# code should then call back into the objective-c code and give it the updated value. Below is the C# code that handles the calculation:
public class MyClass
{
static public void Add(int a, int b)
{
updateResult(a + b);
}
[DllImport("__Internal", EntryPoint="updateResult")]
static extern public void updateResult(int result);
}
Here is my code that initializes mono and handles the add method:
#implementation Mono
- (id)init {
self = [super init];
if (self) {
NSBundle *main = [NSBundle mainBundle];
NSString *path = [main bundlePath];
const char *c_path = [path UTF8String];
[main autorelease];
[path autorelease];
chdir (c_path);
setenv ("MONO_PATH", c_path, 1);
setenv ("MONO_XMLSERIALIZER_THS", "no", 1);
setenv ("DYLD_BIND_AT_LAUNCH", "1", 1);
setenv ("MONO_REFLECTION_SERIALIZER", "yes", 1);
#if defined (__arm__)
mono_aot_register_module (mono_aot_module_mscorlib_info);
mono_aot_register_module (mono_aot_module_Math_info);
mono_jit_set_aot_only (TRUE);
#endif
mono_jit_init("MonoTouch");
MonoAssembly *assembly = mono_assembly_open("Math.dll", NULL);
MonoImage *img = mono_assembly_get_image(assembly);
MonoClass *cls = mono_class_from_name(img, "Math", "MyClass");
MonoMethodDesc *methodDesc = mono_method_desc_new("Math.MyClass:Add", TRUE);
_addMethod = mono_method_desc_search_in_class(methodDesc, cls);
}
return self;
}
- (void)addA:(int)a plusB:(int)b {
void *params[] = { &a, &b };
mono_runtime_invoke(_addMethod, NULL, params, NULL);
}
#end
and here is the definition of the updateResults method:
extern void updateResult(int result) {
printf("Got Result");
}
When the updateResults is called from the C# side of things I get the following exception:
Unhandled Exception: System.EntryPointNotFoundException: updateResult
at (wrapper managed-to-native) Math.MyClass:updateResult (int)
at Math.MyClass.Add (Int32 a, Int32 b) [0x00000] in <filename unknown>:0
I can see the symbol in the binary with the following command:
$ nm Calc | grep updateResult
00002b2e t _updateResult
Setting the MONO_LOG_LEVEL environment variable to debug I get the following output when attempting the PInvoke. It looks like it finds the method and then can't find it:
Mono: DllImport attempting to load: '_Internal'.Mono: Searching for 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResultA'.Mono: Probing 'updateResultA'.Mono: DllImport attempting to load: '_Internal'.Mono: Searching for 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResultA'.Mono: Probing 'updateResultA'.Mono: AOT FOUND AOT compiled code for (wrapper managed-to-native) Math.MyClass:updateResult (int) 0x3bc8 - 0x3d90 0x3dcb
Mono: DllImport attempting to load: '__Internal'.Mono: Searching for 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResult'.Mono: Probing 'updateResultA'.Mono: Probing 'updateResultA'.Unable to resolve pinvoke method 'Math.MyClass:updateResult (int)' Re-run with MONO_LOG_LEVEL=debug for more information.
I've spent quite some time trying to figure this out. From what I've read it seems like this should be pretty trivial, but I can't get it to work. Any help would be much appreciated.
Would it be better to use Selectors?
That is the default path to follow as suggested by the makers of MonoTouch.
It could be a few things, but my first guess is that you aren't using the C symbol from anywhere in native code, and the DCE (dead code elimination) pass is removing it. Try disabling DCE in your Xcode project options.
I've had this problem myself, if you compare an objdump -T and objdump -t of your binary,
you'll find that the "D" flag is missing, so add a -rdynamic to your linker options.
Related
I'm trying to write a password encryption function into my app, following this article.
I wrote a function that runs the CCCalibratePBKDF function and outputs the number of rounds.
const uint32_t oneSecond = 1000;
uint rounds = CCCalibratePBKDF(kCCPBKDF2,
predictedPasswordLength,
predictedSaltLength,
kCCPRFHmacAlgSHA256,
kCCKeySizeAES128,
oneSecond);
This works perfectly, but when I try to implement the next part it all goes wrong.
I can start writing the CCKeyDerivationPBKDF function call and it auto-completes the function and all the parameters. As I go through filling it in all the parameters are also auto-completed.
- (NSData *)authenticationDataForPassword: (NSString *)password salt: (NSData *)salt rounds: (uint) rounds
{
const NSString *plainData = #"Fuzzy Aliens";
uint8_t key[kCCKeySizeAES128] = {0};
int keyDerivationResult = CCKeyDerivationPBKDF(kCCPBKDF2,
[password UTF8String],
[password lengthOfBytesUsingEncoding: NSUTF8StringEncoding],
[salt bytes],
[salt length],
kCCPRFHmacAlgSHA256,
rounds,
key,
kCCKeySizeAES128);
if (keyDerivationResult == kCCParamError) {
//you shouldn't get here with the parameters as above
return nil;
}
uint8_t hmac[CC_SHA256_DIGEST_LENGTH] = {0};
CCHmac(kCCHmacAlgSHA256,
key,
kCCKeySizeAES128,
[plainData UTF8String],
[plainData lengthOfBytesUsingEncoding: NSUTF8StringEncoding],
hmac);
NSData *hmacData = [NSData dataWithBytes: hmac length: CC_SHA256_DIGEST_LENGTH];
return hmacData;
}
But as soon as I hit ; it marks an error saying "No matching function for call to 'CCKeyDerivationPBKDF'" and it won't build or anything.
I've imported CommonCrypto/CommonKeyDerivation.h and CommonCrypto/CommonCryptor.h as both of these were necessary for the enum names.
First, make sure that you haven't done anything funny with your include path (in particular, I do not recommend #HachiEthan's solution, which just confuses things). In general, leave this alone, and specifically don't add things like /usr/include to it. Make sure you've added Security.framework to your link step. This is the usual cause of problems.
The biggest thing you want to be sure of is that you're getting the iOS 5 Security.framework (rather than some other version like the OS X 10.6 or iOS 4 versions). But my suspicion is that you have a problem with your build settings.
If you want to see a framework that does all of this for reference, take a look at RNCryptor.
Right, I've found the problem (and solution).
Because I was using ZXing I had to rename the .m file to .mm so it could run the C++ stuff in the ZXing library.
I don't know why but renaming the file this way broke the CCKeyDerivationPBKDF function.
I've now moved the crypto code into it's own class and left it as .m and all I need now is to include the two imports as I did in the original post.
I didn't have to include any frameworks or anything.
I have added all lua source files in xcode, then build successfully, but have error when run.
after load the lua file, it comes out the error when use pcall method.
Here is the code:
p_lua_stack_ = luaL_newstate();
luaL_openlibs(p_lua_stack_);
FilePathManager *m = [FilePathManager sharedInstance];
int r = luaL_loadfile(p_lua_stack_, [[m llkFacadeFilePath] UTF8String]);
DLog(#"%#", [m llkFacadeFilePath]);
DPRINT("%d", r);
//DPRINT("%d", lua_pcall(p_lua_stack_, 0, 0, 0));
int cr = lua_pcall(p_lua_stack_, 0, 0, 0);
LuaStateUtil *util = LuaStateUtil::GetSharedInstancePointer();
util->PrintPcallReturnValue(cr); //print return value info
DPRINT("%s", lua_tostring(p_lua_stack_, -1)); //when run to this line, the output is...
The output is:...4-489C-4A40-8582-F734FAAC428D/LLK.app/llk_facade.lua:1: attempt to call global 'module' (a nil value)
Then I am totally confused because "module" is a library method of Lua.
Who can help me, please?
maybe this question read a little hard, i'm not good at English.
If that is Lua 5.2, you need to enable module by defining LUA_COMPAT_MODULE.
I read a very interesting blog about implementing some anti-piracy protection into your apps. Some of them dont work anymore, some of them do. The 2 ones that still are effective to an extent are the 2 last ones listed.
http://shmoopi.wordpress.com/2011/06/19/27/
The one I'm interested in is the very last one. Code below. I've implemented this in my AppDelegate.m
Anti piracy via the encryption check.
Required Headers
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <TargetConditionals.h>
Encryption Struct
#if TARGET_IPHONE_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
#define LC_ENCRYPTION_INFO 0x21
struct encryption_info_command
{
uint32_t cmd;
uint32_t cmdsize;
uint32_t cryptoff;
uint32_t cryptsize;
uint32_t cryptid;
};
#endif
Needed Methods
int main (int argc, char *argv[]);
static BOOL is_encrypted ()
{
const struct mach_header *header;
Dl_info dlinfo;
/* Fetch the dlinfo for main() */
if (dladdr(main, &dlinfo) == 0 || dlinfo.dli_fbase == NULL)
{
NSLog(#"Could not find main() symbol (very odd)");
return NO;
}
header = dlinfo.dli_fbase;
/* Compute the image size and search for a UUID */
struct load_command *cmd = (struct load_command *) (header+1);
for (uint32_t i = 0; cmd != NULL && i < header->ncmds; i++)
{
/* Encryption info segment */
if (cmd->cmd == LC_ENCRYPTION_INFO)
{
struct encryption_info_command *crypt_cmd = (struct encryption_info_command *) cmd;
/* Check if binary encryption is enabled */
if (crypt_cmd->cryptid < 1)
{
return NO;
}
return YES;
}
cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
}
return NO;
}
This method checks to see if the binary is still encrypted.
When I run this on the device attached to x-code it gives me a false positive on this line
if (crypt_cmd->cryptid < 1)
{
NSLog(#"Pirated from (crypt_cmd->cryptid < 1) ");
return NO;
}
I was wondering is it possible that the builds xcode puts onto the device for debugging purposes not encrypted? And its only encrypted when the build is submitted to Apple for use on iTunes. Hence why I am getting this false positive when check the code.
Many Thanks,
-Code
This code won't work successfully on a 64-bit device like the iPhone 5s. The header has been changed from mach_header to mach_header_64 and the command ID is now LC_ENCRYPTION_INFO_64.
What I did was to read the header and then see what the magic number was. If it's MH_MAGIC_64 then you're on a 64-bit device and you need to use the mach_header_64 struct and look for LC_ENCRYPTION_INFO_64 (defined as 0x2C) instead of LC_ENCRYPTION_INFO.
A better otool command to see whether a file is encrypted or not is:
otool -arch armv7 -l YourAppName | grep crypt
I have been looking into this recently as well and tested with the same results. It turns out this code is telling you YES or NO based on whether the binary is encrypted with Apple's FairPlay DRM. Any debug or ad-hoc builds you do will say NO.
You can see the same information on your binary or any iPhone apps you have purchased using the otool command-line tool.
For your own binaries, find the binary in your project under e.g. build/Debug-iphoneos/MyApp.app and run (from Terminal)
otool -l MyApp | more
Scan through for cryptid in the LC_ENCRYPTION_INFO section. Since this is a debug build it will be 0. If you have synched your phone to your computer, check under ~/Music/iTunes/Mobile Applications and pick an .ipa file. Unzip it and try otool against the binary from the .ipa and it should have 1 for the cryptid.
It looks like this is looking for the signature block in the dyload header. This means that you're only going to see this on code which is signed. Chances are that your code isn't being automatically signed for debugging (unnecessary), although it will be signed when it goes to the device.
You might want to make this entire check conditional on the project running on an iOS device instead of in the simulator. Any binary sent to an iOS device must be signed.
#if !(TARGET_IPHONE_SIMULATOR)
your check
#endif //
I'm trying to get the caller number (for jailbroken devices) with this code:
extern CFTypeRef CTCallCopyName(void*, CTCall* call);
NSLog(#"%#", CTCallCopyName(NULL, (CTCall*)call));
I receive the error:
"CTCallCopyName(void*, CTCall*)", referenced from:
ld: symbol(s) not found for architecture armv6
I have Core Telephony linked with my project.
Maybe my prototype is wrong... i don't know. Any ideas?
Xcode 3, sdk 4
If you're calling this API in a .mm file, you have to declare it like extern "C" void foo(void); As far as I know, on iOS 5 ~ 7, you should use CTCallCopyAddress instead, the prototype is:
extern "C" CFStringRef CTCallCopyAddress(CFAllocatorRef, CTCallRef);
Notice that the second arg is a CTCallRef rather than a CTCall, which means you can't send it CTCall class methods (although some of them work). Besides linking CoreTelephony.framework, you can also load this symbol dynamically, as shown below:
static CFStringRef (*CTCallCopyAddress)(CFAllocatorRef, CTCallRef);
void Foo(CTCallRef call)
{
void *libHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony", RTLD_LAZY);
CTCallCopyAddress = (CFStringRef (*)(CFAllocatorRef, CTCallRef))dlsym(libHandle, "CTCallCopyAddress");
NSString *address = (NSString *)CTCallCopyAddress(kCFAllocatorDefault, call);
NSLog(#"The caller's address is %#", address);
[address release];
dlclose(libHandle);
}
BTW, I can't get CTCallCopyName to work in SpringBoard on iOS 5, haven't figured it out or tried on other systems yet. Hope this information helps!
EDIT: Just give it another try on iOS 5, CTCallGetID is the right function to get the caller ID in the addressbook, whose prototype is ABRecordID CTCallGetID(CTCallRef). iOS 6 and 7 are possibly the same.
How is it done? What steps do I need to take and what pitfalls and gotchas are there to consider?
I've gotten this to work, thanks to some inside help over at the Apple Devforums, you should sign up if you're a dedicated IPhone developer.
First thing's first, it's __asm__(), not plain asm().
Secondly, by default, XCode generates a compilation target that compiles inline assembly against the ARM Thumb instruction set, so usat wasn't recognized as a proper instruction. To fix this, do "Get Info" on the Target. Scroll down to the section "GCC 4.0 - Code Generation" and uncheck "Compile for Thumb". Then this following snippet will compile just fine if you set the Active SDK to "Device"
inline int asm_saturate_to_255 (int a) {
int y;
__asm__("usat %0, #8, %1\n\t" : "=r"(y) : "r"(a));
return y;
}
Naturally, now it won't work with the IPhone Simulator. But TargetConditionals.h has defines you can #ifdef against. Namely TARGET_OS_IPHONE and TARGET_IPHONE_SIMULATOR.
I write quite a bit of ARM Cortex-A8 assembly-code. The CPU on the iPhone is an ARM11 (afaik) so the core instruction set is the same.
What exactly are you looking for? I could give you some examples if you want.
EDIT:
I just found out that on the iPhone you have to use the llvm-gcc compiler. As far as I know it should understand the inline assembler syntax from GCC. If so all the ARM inline assembler tutorials will work on the iPhone as well.
Here is a very minimal inline assembler function (in C). Could you please tell me if it compiles and works on the iphone? If it works I can rant a bit how to do usefull stuff in ARM inline assembler, especially for the ARMv6 architecture and the DSP extensions.
inline int saturate_to_255 (int a)
{
int y;
asm ("usat %0, #8, %1\n\t" : "=r"(y) : "r"(a));
return y;
}
should be equivalent to:
inline int saturate_to_255 (int a)
{
if (a < 0) a =0;
if (a > 255) a = 255;
return a;
}
The registers can also be used explicitly in inline asm
void foo(void) {
#if TARGET_CPU_ARM64
__asm ("sub sp, sp, #0x60");
__asm ("str x29, [sp, #0x50]");
#endif
}
Thumb is recommended for application which do not require heavy float operation. Thumb makes the code size smaller and results also in a faster code execution.
So you should only turn Thumb off for application like 3D games...
Background
Now is 2021 year -> other answer seems is too old?
the most iOS device(iPhone etc.) is ARM 64bit: arm64
Inline assembly on the iPhone
asm keyword
GNU/GCC compiler
standard C (compile flag: -ansi / -std): use __asm__
GNU extensio: use asm
ARM compiler: use __asm
asm syntax
AFAIK, there many asm syntax
asm syntax
AT&T syntax ~= GNU syntax ~= UNIX syntax
Intel syntax
ARM syntax
here only focus on most common used GNU/GCC syntax
GNU/UNIX syntax
Basic Asm
asm("assembly code");
__asm__("assembly code");
Extended Asm
asm asm-qualifiers ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
My Example code
environment
dev
macOS
IDE: XCode
compiler: clang
running
iOS - iPhone
hardware arch: ARM64
inline asm to call svc 0x80 for ARM64 using Extended Asm
inline asm inside ObjC code
// inline asm code inside iOS ObjC code
__attribute__((always_inline)) long svc_0x80_syscall(int syscall_number, const char * pathname, struct stat * stat_info) {
register const char * x0_pathname asm ("x0") = pathname; // first arg
register struct stat * x1_stat_info asm ("x1") = stat_info; // second arg
register int x16_syscall_number asm ("x16") = syscall_number; // special syscall number store to x16
register int x4_ret asm("x4") = -1; // store result
__asm__ volatile(
"svc #0x80\n"
"mov x4, x0\n"
: "=r"(x4_ret)
: "r"(x0_pathname), "r"(x1_stat_info), "r"(x16_syscall_number)
// : "x0", "x1", "x4", "x16"
);
return x4_ret;
}
call inline asm
// normal ObjC code
#import <sys/syscall.h>
...
int openResult = -1;
struct stat stat_info;
const char * filePathStr = [filePath UTF8String];
...
// call inline asm function
openResult = svc_0x80_syscall(SYS_stat64, filePathStr, &stat_info);
Doc
GCC-Inline-Assembly-HOWTO (ibiblio.org)
Extended Asm (Using the GNU Compiler Collection (GCC))
Procedure Call Standard for the Arm® 64-bit Architecture
ARM GCC Inline Assembler Cookbook
ConvertBasicAsmToExtended - GCC Wiki
ios - fork() implementation by using svc call - Stack Overflow
linux - ARM inline asm: exit system call with value read from memory - Stack Overflow