我刚刚开始在我的 Mac Silicon M2 上学习 ARM 汇编。我编写了一个程序,它只获取其命令行参数(又名 argv)并使用 write 系统调用打印它们(并返回它们的编号 argc)。
该程序有效:它使用我调用它的确切路径输出二进制文件的完整路径。
但是当我使用 lldb 检查内存中我确信从中获取 argv[0] 的位置时,它总是包含绝对路径。
这是因为 lldb 总是使用绝对路径运行它吗?有办法找出来吗?如果是,这是 lddb 应该做的还是一个错误?
这是我的程序的源代码。
1 // ARM assembly program on M2 for mac OS 14.7.1
2 // print argv separated by newlines, return argc
3 .global _start
4 .p2align 2
5 // input from OS: W0 ... argc
6 // X1 ... **char argv
7 // argv[0] points to NULL separated concatenation
8 // of elements of argv (for some reason)
9 //
10 // WORKING MEM: W19 argc
11 // X1 previous *argv for print
12 // X2 current str length
13 // W21 argc loop decr counter
14 // X22 *chr argv loop incr counter
15 // X23 *chr newline
16
17 _start:
18 mov W19, W0 // W0 holds the number of args, copy
19 adr X23, chr_newline // make *"\n" available for printing
20 // set up loop to print all arguments
21 mov W21, W19 // put argc into loop counter
22 ldr X22, [X1] // X22 := *char argv[0]
23 loop_argv:
24 bl handle_arg // print one argument
25 sub W21, W21, #1 // decr loop counter
26 cmp W21, #0 // loop if > 0
27 b.gt loop_argv
28 // exit
29 mov W0, W19 // return code := argc
30 mov X16, #1 // service code for termination
31 svc #0x80 // make sys call
32 // local function handle_arg
33 handle_arg:
34 mov X1, X22 // save start *char in X1
35 mov X2, #0 // X2 should contain len at end
36 count_chars_loop: // search for NULL char separating args
37 ldrb W0, [X22], #1 // W0 = &X22, incr *char X22 after
38 cmp W0, #0 // check if prev X22 pointed to NULL char
39 add X2, X2, #1 // incr len
40 b.gt count_chars_loop
41 sub X2, X2, #1 // correct for overcounting
42 // X22 = *next argv now
43 //print argv[i]
44 mov X0, #1 // to stdout
45 // *char next argv is already in X1
46 // len(argv[i]) is already in X2
47 mov X16, #4 // nr for write call
48 svc #0x80 // make sys call
49 // print newline
50 mov X0, #1 // to stout
51 mov X1, X23 // X1 = *char newline
52 mov X2, #1 // len("\n")
53 mov X16, #4 // nr for write call
54 svc #0x80 // make sys call
55 ret
56 .align 2
57 chr_newline: .ascii "\n"
我使用
编译并链接它as get_args.s -o get_args.o
ld -o bin/get_args_min get_args_min.o -lSystem -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -e _start -arch arm64
这是我在命令行上看到的:
me@c get_args % ./bin/get_args_min test test
./bin/get_args_min
test
test
me@c get_args %
注意相对路径。 (我也尝试用绝对路径调用它,然后我确实在终端上得到了它。)但是我们打印的位置似乎always包含二进制文件的完整绝对路径。为了检查这一点,我使用了
lldb -- ./bin/get_args_min test test
...然后是 lldb 命令
b handle_args
r
re r
...然后复制X22中的地址,然后
memory read [PASTE]
这可能是由
lldb
启动程序的方式引起的,即使用其绝对路径,而 shell 使用您指定的路径(相对或绝对)。
当您启动
lldb
时,它会显示它将启动的可执行文件。即使您没有向可执行文件路径添加目录前缀,它也会将可执行文件设置为其绝对路径:
$ lldb -- get_args_min foo bar
(lldb) target create "get_args_min"
Current executable set to '/tmp/get_args_min' (arm64).
我对
man execve
的理解是,argv[0]
的值不是标准化的,它由调用程序(因此shell或lldb
)来设置它。