A pesar de que la respuesta aceptada es más que suficiente, me gustaría dar una respuesta explícita, ya que hay algunas otras respuestas que pueden confundir.
más importantes (para más información ver ejemplos más abajo): en x86-64 los argumentos de línea de comandos se pasan a través de la pila:
(%rsp) -> number of arguments
8(%rsp) -> address of the name of the executable
16(%rsp) -> address of the first command line argument (if exists)
... so on ...
Es diferente de parámetro de la función que pasa en x86-64, que utiliza %rdi
, %rsi
y así sucesivamente.
Una cosa más: uno no debe deducir el comportamiento de la ingeniería inversa de la C main
-función. C runtime proporciona el punto de entrada _start
, ajusta los argumentos de la línea de comandos y llama al main
como una función común. Para verlo, consideremos el siguiente ejemplo.
Sin tiempo de ejecución C/GCC con -nostdlib
vamos a ver este sencillo programa x86-64 ensamblador, que no hacen más que devuelve 42:
.section .text
.globl _start
_start:
movq $60, %rax #60 -> exit
movq $42, %rdi #return 42
syscall #run kernel
Construimos con:
as --64 exit64.s -o exit64.o
ld -m elf_x86_64 exit64.o -o exit64
o con
gcc -nostdlib exit64.s -o exit64
carreras en GDB con
./exit64 first second third
y se detiene en el punto de ruptura en _start
. Vamos a comprobar los registros:
(gdb) info registers
...
rsi 0x0 0
rdi 0x0 0
...
No había nada. ¿Qué hay de la pila?
(gdb) x/5g $sp
0x7fffffffde40: 4 140737488347650
0x7fffffffde50: 140737488347711 140737488347717
0x7fffffffde60: 140737488347724
Así que el primer elemento en la pila es 4
- argc
la esperada. Los siguientes 4 valores se parecen mucho a los punteros. Miremos el segundo puntero:
(gdb) print (char[5])*(140737488347711)
$1 = "first"
Como era de esperar, es el primer argumento de línea de comando.
Así que hay evidencia experimental de que los argumentos de la línea de comando se pasan a través de la pila en x86-64. Sin embargo, solo leyendo el ABI (como sugirió la respuesta aceptada) podemos estar seguros de que este es realmente el caso.
Con tiempo de ejecución C
Tenemos que cambiar ligeramente el programa, el cambio de nombre _start
en main
, ya que el punto _start
entrada es proporcionada por el tiempo de ejecución C.
.section .text
.globl main
main:
movq $60, %rax #60 -> exit
movq $42, %rdi #return 42
syscall #run kernel
lo construimos con (C tiempo de ejecución se utiliza por defecto):
gcc exit64gcc.s -o exit64gcc
carreras en GDB con
./exit64gcc first second third
y parar en el punto de ruptura en main
. ¿Qué hay en la pila?
(gdb) x/5g $sp
0x7fffffffdd58: 0x00007ffff7a36f45 0x0000000000000000
0x7fffffffdd68: 0x00007fffffffde38 0x0000000400000000
0x7fffffffdd78: 0x00000000004004ed
No le resulta familiar. Y registros?
(gdb) info registers
...
rsi 0x7fffffffde38 140737488346680
rdi 0x4 4
...
Podemos ver que rdi
contiene el valor argc
. Pero si ahora inspeccionamos el puntero en rsi
pueden suceder cosas extrañas:
(gdb) print (char[5])*($rsi)
$1 = "\211\307???"
Pero espera, el segundo argumento de la función main
en C no es char *
, pero char **
también:
(gdb) print (unsigned long long [4])*($rsi)
$8 = {140737488347644, 140737488347708, 140737488347714, 140737488347721}
(gdb) print (char[5])*(140737488347708)
$9 = "first"
Y ahora Encontramos nuestros argumentos, que se pasan a través de registros como lo sería para una función normal en x86-64.
Conclusión: Como podemos ver, el es una diferencia respecto a paso de los argumentos de línea de comandos entre el código de tiempo de ejecución utilizando C y código que no lo hace.
Las respuestas del enlace solo son frágiles. Esa página no funciona para mí. * www.x86-64.org no envió ningún dato. ERR_EMPTY_RESPONSE * – doug65536