I am currently writing a project using c language and arm assembly directly.
And I compiled the project for Android, everything was fine.
But when I compiled the project on MacOS (with Apple silicon), it failed. And I realized that the codes compiled on MacOS will be added a prefix _
to all symbols except for ASM codes.
I previously thought only ASM codes will be added a prefix, and after I took a deep look into the compiled codes, I found out that I was wrong.
For example:
int test_func();
int main() {
printf("%d\n", test_func());
return 0;
}
.global test_func
test_func:
mov x0, x1
ret
When compiling this code on MacOS, the main
function is actually calling to _test_func()
instead of test_func()
.
When compiling this code for Android, the test_func
symbol is still itself.
So I am wondering if there is an elegant way to support both platforms without changing too much source code.
Sorry, I made a mistake about this problem.
The problem is, on MacOS, it will automatically add _
prefix to all function, except our own assembly code.
So when calling test_func()
in the main()
, it is actually calling to _test_func()
.
I will edit this to previous question.
Then we can keep all the function in c file unchanged, and define the assembly code like this:
#ifdef __APPLE__
#define DEFINE_FUNC(func) \
.global _##func; \
_##func
#define END_FUNC(...) /*_*/
#else
#define DEFINE_FUNC(func)\
.global func; \
.type func,%function; \
func
#define END_FUNC(func)\
.size func,.-func;
#endif
DEFINE_FUNC(test_func):
mov x0, x1
ret
END_FUNC(test_func)
This #define
macro seems good but it still failed when compiling.
Then I realized that the multi-line #define
will be extended to only one line (at least does so on MacOS and Linux). And the ;
is treated as comment on MacOS, so only the first line in #define
will be added to the compiled object.
So the compiled object for previous example is like:
// After extended
.global _test_func; _test_func:
mov x0, x1
ret
// After compiled
.global _test_func
mov, x0, x1
ret
So there is no symbol _test_func
defined at all!
Then I found another way to solve this -- using .macro
instead of #define
. The problem of #define
is that we can't pass multi-line instruction, but .macro
works fine:
.macro define_func func
.global _\func
_\func:
.endm
#ifdef __APPLE__
#define DEFINE_FUNC(func) define_func func
#define END_FUNC(...) /*_*/
#else
#define DEFINE_FUNC(func)\
.global func; \
.type func,%function; \
func:
#define END_FUNC(func)\
.size func,.-func;
#endif
DEFINE_FUNC(test_func)
mov x0, x1
ret
END_FUNC(test_func)
So now I think I solved this problem elegantly. If there is a better way, please post your idea without any hesitation.