打开系统调用 56 ARMv8 失败

问题描述 投票:0回答:1

我正在尝试使用 syscall 56/dev/input/js0 打开我的 Xbox 游戏手柄。我已验证设备在给定路径上的存在。包括通过使用 open() 用 C 编写的测试程序。然而,程序继续分支FailExit

.global main

.section .text
.align 2
main:
    ldr x0, =GamepadPath
    mov x1, #0
    mov x8, #56
    svc #0

    cmp x0, #0
    blt FailExit 

    mov x0, #1
    ldr x1, =SuccessMsg
    mov x2, #25
    mov x8, #64
    svc #0 

    mov x0, #0
    mov x8, #93
    svc #0

FailExit:
    mov x0, #1
    ldr x1, =ErrorMsg
    mov x2, #25
    mov x8, #64
    svc #0
    mov x0, #0
    mov x8, #93
    svc #0

.section .data

.section .rodata
GamepadPath: .asciz "/dev/input/js0"
SuccessMsg: .asciz "Gamepad Connected\n\n"
ErrorMsg: .asciz "Gamepad Not Available\n\n"

.section .bss

我尝试理解一些参考资料,包括:

openat(2) - Linux 手册页

ARM64.Syscall.sh

让我感到困惑的是,Syscall 56OpenAt在x0处的第一个参数应该是由系统调用Open设置的返回值,我在ARMv8 Linux的任何参考中都找不到它。

linux assembly system-calls arm64 armv8
1个回答
0
投票

linux.die.net 往往有过时版本的手册页。 man7.org 更好。 您可以在这里阅读:

dirfd 参数与路径名结合使用 论证如下:

• 如果 pathname 中给出的路径名是绝对路径名,则 dirfd 是 被忽略了。

这就是你的情况;

/dev/input/js0
是绝对路径(以
/
开头)。

因此,只需将您喜欢的任何内容(例如 0 或 -1)作为

dirfd
第一个参数传递给
openat
系统调用即可。 这意味着路径名成为第二个参数,标志成为第三个参数。

尝试

    mov x0, #-1
    ldr x1, =GamepadPath
    mov x2, #0
    mov x8, #56
    svc #0

openat
添加的值适用于像foo/bar/baz这样的
相对
路径。 对于正常的
open
,这总是相对于当前工作目录得到解决;因此,如果您当前的工作目录是
/blah
,那么
open("foo/bar/baz")
将始终打开
/blah/foo/bar/baz
。 您可以通过传递特殊值
openat
(在
AT_FDCWD
中定义为
<fcntl.h>
)作为第一个参数,从
-100
获得相同的行为。 因此,在您的代码中,如果您想在使用相对路径时复制
open
,只需执行
mov x0, #-100
并使用其余参数填充
x1
x2
x3

但是你也可以先打开一个目录并传递它的 fd。 因此,如果您当前的工作目录是

/blah
但您确实想相对于
/gurgle
打开,您可以这样做

dirfd = openat(-1, "/gurgle", O_RDONLY | O_DIRECTORY);
fd = openat(dirfd, "foo/bar/baz", O_RDONLY);

这将打开

/gurgle/foo/bar/baz

使用文件描述符可以帮助避免竞争条件。 假设您要创建一个文件

/foo/new
,但前提是
/foo/old
已存在于该目录中。 如果你做了显而易见的事情

fdold = open("/foo/old", O_RDONLY);
if (fdold >= 0) {
    fdnew = open("/foo/new", O_CREAT | O_WRONLY, 0644)
}

那么问题是,在两次调用

open
之间,有人可以重命名并重新创建目录
/foo
,或者将其重新创建为指向其他位置的符号链接。 然后,您最终可能会在
包含 new 的目录中创建
old

openat
让您避免这种情况:

dirfd = openat(-1, "/foo", O_RDONLY | O_DIRECTORY);
fdold = openat(dirfd, "old", O_RDONLY);
if (fdold) {
    openat(dirfd, "new", O_CREAT | O_WRONLY, 0644)
}

现在这两个文件肯定会存在于同一个目录中,无论该目录的名称是否同时从

foo
更改为其他名称。

© www.soinside.com 2019 - 2024. All rights reserved.