问题
I am trying to run some inline assembly code for aarch64 from Android Studio 3.4.2 and I got a compilation error error: Don't know how to handle indirect register inputs yet for constraint 'r'
.
My code snippet as follows
std::string system_file = "/system/bin/sh";
std::int64_t file_descriptor = -1;
#ifdef __aarch64__
__asm__ volatile("mov x8, #180\n\t"
"mov x0, %1\n\t"
"mov x1, #0\n\t"
"svc #1\n\t"
"mov %0, x0\n\t"
:"=r"(file_descriptor)
:"r"(system_file)
:"x0","x1","x8"
);
#endif
ARM64 syscalls based on this article
https://reverseengineering.stackexchange.com/questions/16917/arm64-syscalls-table
and taken from
https://github.com/torvalds/linux/blob/v4.17/include/uapi/asm-generic/unistd.h
I am not sure if the error is due to Android Studio or am I doing something wrong here? Any advice is appreciated.
**** EDIT ****
I think I may have been looking at the wrong syscall number. Instead, I should be looking at
#define __NR_openat 56
__SC_COMP(__NR_openat, sys_openat, compat_sys_openat)
Now I am trying to do this and it seems to be wrong.
std::string system_file = "/system/bin/sh";
const char *ptr = system_file.c_str();
std::int64_t file_descriptor = 0;
register std::int64_t x8 asm("x8") = 56;
register std::int64_t x0 asm("x0") = 0;
register std::int64_t x2 asm("x2") = 0;
__asm__ volatile("svc #1"
:"=r"(file_descriptor)
:"r"(x0),"r"(ptr),"r"(x2),"r"(x8)
:"memory"
);
__android_log_print(ANDROID_LOG_DEBUG,"native_code","file_descriptor: %i",file_descriptor);
I can see a number "56" returned in logcat but it is the same number regardless the file exists or not. Is it a coincidence that it is the same as the syscall number?
回答1:
As a general rule, you want to move as much of the code out of the inline asm as possible. In this case for instance, you are moving #180 to x8 to indicate the service number to invoke. But what if you want to open 2 files in a row, passing 180 in x8 both times? Ideally you'd want to avoid setting the identical value into the same register twice if you could, right? But by putting the mov
inside the asm, you are forcing the value to be set every time.
You can avoid that by moving the assignments out of the asm. While I don't have an arm64 platform to run this on, the output from godbolt looks right:
std::string system_file = "/system/bin/sh";
const char *ptr = system_file.c_str();
register std::int64_t file_descriptor asm("x0");
register std::int64_t x8 asm("x8") = 180;
register std::int64_t x1 asm("x1") = 0;
__asm__ volatile("svc #1"
:"=r"(file_descriptor)
:"0"(ptr),"r"(x1),"r"(x8)
:"memory"
);
Since x1 and x8 are listed as inputs (ie after the 2nd colon), gcc assumes their value is unchanged. And since the assignments took place in C code, it knows what values are there too.
The "0" might look a bit odd, but it's saying that ptr
will be in the same place as parameter #0 (ie file_descriptor, which uses asm("x0")
). So the input will be ptr, the output will be file_descriptor, and both use the same register.
I'll also mention that all the svc
samples I've seen use svc #0
.
来源:https://stackoverflow.com/questions/57355889/android-studio-64-bit-inline-arm-assembly