admin管理员组

文章数量:1134571

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.

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.

Share Improve this question edited Jan 8 at 6:32 Tall asked Jan 8 at 2:50 TallTall 1214 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

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.

本文标签: cHow to elegantly support ARM assembly on both MacOS and AndroidStack Overflow