Estou apenas começando a aprender assembly ARM no meu Mac Silicon M2. Escrevi um programa que apenas pega seus argumentos de linha de comando (também conhecidos como argv) e os imprime (e retorna seu número, argc) usando a chamada de sistema write .
O programa funciona: ele exibe o caminho completo para o binário, usando exatamente o caminho que eu o chamei.
Mas quando uso o lldb para examinar os locais na memória dos quais estou convencido de que argv[0] foi retirado, ele sempre contém o caminho absoluto.
Isso ocorre porque o lldb sempre o executa usando o caminho absoluto? Existe uma maneira de descobrir? Se sim, é isso que o lddb deve fazer ou é um bug?
Aqui está o código fonte do meu programa.
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"
Eu compilo e vinculo usando
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
Aqui está o que vejo na linha de comando:
me@c get_args % ./bin/get_args_min test test
./bin/get_args_min
test
test
me@c get_args %
Observe o caminho relativo. (Eu tentei chamá-lo com o caminho absoluto também, e então eu o obtive no terminal.) Mas o local de onde imprimimos parece sempre conter o caminho absoluto completo para o binário. Para verificar isso, eu usei
lldb -- ./bin/get_args_min test test
...então os comandos lldb
b handle_args
r
re r
...então copiei o endereço no X22, então
memory read [PASTE]