Reputation: 35993
Ok, I can store blocks on NSArrays using something like this:
NSArray *myArray = @[[myBlock1 copy], [myBlock2 copy]];
and run that code later by doing, for example:
myBlockType runBlock = myArray[0];
runBlock(); // run baby, run
What about the C equivalent to this? Is that possible?
Upvotes: 0
Views: 87
Reputation: 108978
If the Operating System allows you to do that, you can assign the address of an array to a function pointer and call the code in the array using the name of that pointer.
typedef void (*fx_t)(void);
int main(void) {
fx_t udf;
unsigned char code[1000] = "<<machine code instructions>>";
udf = code; /* UB: assignment of object pointer to non-object pointer */
/* illegal assignment according to the Standard */
udf();
return 0;
}
As per requests in comments, here is a complete example that works on my computer (FreeBSD 9.2 on amd64)
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
typedef int (*fx_t)(void);
int main(void) {
int a = -1;
fx_t udf;
unsigned char code[1000] = "\xb8\x2a\x00\x00\x00" // mov $0x2a,%eax
"\xc3"; // retq
void *codeaddr = code;
size_t length = 4096; /* size of a page */
if (mprotect(codeaddr, length, PROT_READ | PROT_WRITE | PROT_EXEC)) {
perror("mprotect");
exit(EXIT_FAILURE);
}
udf = (void*)code;
a = udf(); // call the code in the `code` string
printf("a is now %d.\n", a); // expect 42, changed by the code in `code`
code[1] = 24; // w00t! self changing code
a = udf();
printf("a is now %d.\n", a); // expect 24
return 0;
}
To get the bytes for my code
, I compiled a very simple int fortytwo(void) { return 42; }
to object file and then objdump -d
it and tried the bytes that seemed relevant (I don't know assembly language)
0000000000000000 <fortytwo>: 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: b8 2a 00 00 00 mov $0x2a,%eax 9: c9 leaveq a: c3 retq b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Upvotes: 0
Reputation: 6579
This works:
typedef void (^MyBlockType)(void);
MyBlockType blocks[100];
for(int i = 0; i < 100; i++) {
MyBlockType block= ^{printf("Run!");};
blocks[i] = block;
}
MyBlockType thisBlock = blocks[0];
thisBlock();
Upvotes: 2