内联 ARM64 系统调用给出了错误的 return 值
Inlined ARM64 system call giving the wrong return value
这是我的代码。
long doSystemCall(const char *path) {
register long x0 asm("x0") = 0;
register long x1 asm("x1") = (long) path;
register long x2 asm("x2") = 0;
register long x3 asm("x3") = 0;
register long x8 asm("x8") = __NR_faccessat;
__asm__ volatile("svc #0"
:"=r"(x0)
:"0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8)
:"memory"
);
__android_log_print(ANDROID_LOG_INFO, "SYSCALL", "Result: %li", x0);
return x0;
}
它给出的 return 值是 0
、-2
或 -13
,但是 faccessat
应该只 return 0
或 -1
。我该如何解决这个问题?
我的代码反编译后的伪代码是这样的。
signed __int64 __fastcall sub_E558(const char *a1)
{
signed __int64 v1; // ST30_8
v1 = linux_eabi_syscall(__NR_faccessat, 0, a1, 0, 0);
__android_log_print(4LL, "SYSCALL", "Result: %li", v1);
return v1;
}
这些是函数的说明。
SUB SP, SP, #0x50
STP X29, X30, [SP,#0x40+var_s0]
ADD X29, SP, #0x40
STUR X0, [X29,#var_8]
MOV X0, XZR
STUR X0, [X29,#var_10]
LDUR X8, [X29,#var_8]
STUR X8, [X29,#var_18]
STR X0, [SP,#0x40+var_20]
STR X0, [SP,#0x40+var_28]
MOV W9, #0x30
MOV W8, W9
STR X8, [SP,#0x40+var_30]
LDUR X0, [X29,#var_10]
LDUR X1, [X29,#var_18]
LDR X2, [SP,#0x40+var_20]
LDR X3, [SP,#0x40+var_28]
LDR X8, [SP,#0x40+var_30]
SVC 0
STUR X0, [X29,#var_10]
LDUR X3, [X29,#var_10]
ADRP X1, #aSyscall@PAGE ; "SYSCALL"
ADD X1, X1, #aSyscall@PAGEOFF ; "SYSCALL"
ADRP X2, #aResultLi@PAGE ; "Result: %li"
ADD X2, X2, #aResultLi@PAGEOFF ; "Result: %li"
MOV W0, #4
BL .__android_log_print
LDUR X8, [X29,#var_10]
STR W0, [SP,#0x40+var_34]
MOV X0, X8
LDP X29, X30, [SP,#0x40+var_s0]
ADD SP, SP, #0x50
RET
您将 libc 包装器 API 与直接系统调用 ABI 混淆了——只有 libc 包装器 return 在 errno 中出现错误。直接系统调用将 return 一个小的负值(带有错误代码),至少在 Linux 上。 libc 包装器将测试 return 值,如果它在 -4096..-1 范围内,将取反并将其存储在 errno 中(然后是 return -1)。其他 UNIX 变体 (BSD) return 标志(通常是进位标志)中的错误指示以及 return 寄存器中的错误值。
这是我的代码。
long doSystemCall(const char *path) {
register long x0 asm("x0") = 0;
register long x1 asm("x1") = (long) path;
register long x2 asm("x2") = 0;
register long x3 asm("x3") = 0;
register long x8 asm("x8") = __NR_faccessat;
__asm__ volatile("svc #0"
:"=r"(x0)
:"0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8)
:"memory"
);
__android_log_print(ANDROID_LOG_INFO, "SYSCALL", "Result: %li", x0);
return x0;
}
它给出的 return 值是 0
、-2
或 -13
,但是 faccessat
应该只 return 0
或 -1
。我该如何解决这个问题?
我的代码反编译后的伪代码是这样的。
signed __int64 __fastcall sub_E558(const char *a1)
{
signed __int64 v1; // ST30_8
v1 = linux_eabi_syscall(__NR_faccessat, 0, a1, 0, 0);
__android_log_print(4LL, "SYSCALL", "Result: %li", v1);
return v1;
}
这些是函数的说明。
SUB SP, SP, #0x50
STP X29, X30, [SP,#0x40+var_s0]
ADD X29, SP, #0x40
STUR X0, [X29,#var_8]
MOV X0, XZR
STUR X0, [X29,#var_10]
LDUR X8, [X29,#var_8]
STUR X8, [X29,#var_18]
STR X0, [SP,#0x40+var_20]
STR X0, [SP,#0x40+var_28]
MOV W9, #0x30
MOV W8, W9
STR X8, [SP,#0x40+var_30]
LDUR X0, [X29,#var_10]
LDUR X1, [X29,#var_18]
LDR X2, [SP,#0x40+var_20]
LDR X3, [SP,#0x40+var_28]
LDR X8, [SP,#0x40+var_30]
SVC 0
STUR X0, [X29,#var_10]
LDUR X3, [X29,#var_10]
ADRP X1, #aSyscall@PAGE ; "SYSCALL"
ADD X1, X1, #aSyscall@PAGEOFF ; "SYSCALL"
ADRP X2, #aResultLi@PAGE ; "Result: %li"
ADD X2, X2, #aResultLi@PAGEOFF ; "Result: %li"
MOV W0, #4
BL .__android_log_print
LDUR X8, [X29,#var_10]
STR W0, [SP,#0x40+var_34]
MOV X0, X8
LDP X29, X30, [SP,#0x40+var_s0]
ADD SP, SP, #0x50
RET
您将 libc 包装器 API 与直接系统调用 ABI 混淆了——只有 libc 包装器 return 在 errno 中出现错误。直接系统调用将 return 一个小的负值(带有错误代码),至少在 Linux 上。 libc 包装器将测试 return 值,如果它在 -4096..-1 范围内,将取反并将其存储在 errno 中(然后是 return -1)。其他 UNIX 变体 (BSD) return 标志(通常是进位标志)中的错误指示以及 return 寄存器中的错误值。