Linux ARM上程序寄存器和堆栈的初始状态

Ste*_*ith 6 linux assembly arm

我目前正在Linux上使用ARM程序集作为学习练习.我正在使用'裸'汇编,即没有libcrt或libgcc.任何人都能指出有关堆栈指针和其他寄存器在调用第一条指令之前在程序开始时的状态的信息吗?显然pc/r15指向_start,其余的似乎初始化为0,但有两个例外; sp/r13指向远离我程序的地址,r1指向略高的地址.

对于一些可靠的问题:

  • r1的值是多少?
  • sp中的值是内核分配的合法堆栈吗?
  • 如果没有,分配堆栈的首选方法是什么; 使用brk还是分配静态.bss部分?

任何指针将不胜感激.

Ces*_*arB 6

由于这是Linux,您可以查看内核如何实现它.

寄存器似乎是通过调用start_thread结束设置的load_elf_binary(如果你使用的是现代Linux系统,它几乎总是使用ELF格式).对于ARM,寄存器似乎设置如下:

r0 = first word in the stack
r1 = second word in the stack
r2 = third word in the stack
sp = address of the stack
pc = binary entry point
cpsr = endianess, thumb mode, and address limit set as needed
Run Code Online (Sandbox Code Playgroud)

显然你有一个有效的堆栈.我觉得值r0- r2都是垃圾,你应该阅读,而不是一切从堆栈(你会明白为什么我觉得这个版本).现在,让我们看一下堆栈中的内容.你将从堆栈中读取的内容被填充create_elf_tables.

这里要注意的一件有趣的事情是,这个函数是独立于架构的,因此在每个基于ELF的Linux架构上,相同的东西(大多数)都会被放在堆栈上.以下是堆栈,按您阅读的顺序:

  • 的参数(这是数argcmain()).
  • 一个指向每个参数的C字符串的指针,后跟一个零(这是argvin 的内容main(); argv将指向这些指针中的第一个).
  • 一个指向每个环境变量的C字符串的指针,后跟一个零(这是很少见的envp第三个参数的内容main(); envp将指向这些指针中的第一个).
  • "辅助向量"是一对对(一个类型后跟一个值)的序列,由AT_NULL第一个元素中带有零()的对终止.这个辅助向量有一些有趣且有用的信息,你可以通过运行任何动态链接程序并将LD_SHOW_AUXV环境变量设置为1(例如LD_SHOW_AUXV=1 /bin/true)来查看(如果你使用的是glibc ).根据架构的不同,这也可能会有所不同.

由于此结构对于每个体系结构都是相同的,因此您可以查看SYSV 386 ABI第54页上的绘图,以更好地了解事物如何组合在一起(但请注意,该文档上的辅助矢量类型常量)与Linux使用的不同,所以你应该看看它们的Linux头文件.

现在你可以看到为什么r0- r2垃圾的内容.堆栈中的第一个单词是argc,第二个是指向程序名称(argv[0])的指针,第三个可能是零,因为你调用了没有参数的程序(它会是argv[1]).我想他们都建立了这种方式对于上了年纪a.out的二进制格式,你可以看到在create_aout_tablesargc,argv以及envp在堆栈(所以他们会在结束r0- r2在预期调用顺序main()).

最后,为什么r0你为零而不是一个(argc如果你没有参数调用程序,应该是一个)?我猜测系统调用机器中的某些东西用系统调用的返回值覆盖它(自exec成功以来它将为零).你可以看到kernel_execve(它不使用系统调用机制,因为它是内核在想要从内核模式执行时调用的内容),它故意r0用返回值覆盖do_execve.


Ric*_*ton 3

以下是我使用编译器启动 Linux/ARM 程序的方法:

/** The initial entry point.
 */
asm(
"       .text\n"
"       .globl  _start\n"
"       .align  2\n"
"_start:\n"
"       sub     lr, lr, lr\n"           // Clear the link register.
"       ldr     r0, [sp]\n"             // Get argc...
"       add     r1, sp, #4\n"           // ... and argv ...
"       add     r2, r1, r0, LSL #2\n"   // ... and compute environ.
"       bl      _estart\n"              // Let's go!
"       b       .\n"                    // Never gets here.
"       .size   _start, .-_start\n"
);
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我只是从 [sp] 的堆栈中获取 argc、argv 和 environ 内容。

一点澄清:堆栈指针指向进程内存中的有效区域。r0、r1、r2 和 r3 是被调用函数的前三个参数。我分别用 argc、argv 和 environ 填充它们。