运行库和程序初始化

入口函数和函数初始化

 程序在进入我们编写的入口之前,就已经初始化好了堆栈,外围IO,全局变量等。
 这些工作都是函数库完成的,他们才是一个独立程序最开始执行的代码。

在这里插入图片描述

入口函数的实现(静态glibc+可执行文件)

 首先我们要明白在PC指向E入口地址执行之前,是谁在handle这个ELF文件?应该是装载器(ld),装载器按照其ELF文件中的Program Header等信息将其相关的部分装载内存中,同时也会将用户的参数和环境变量压入栈中。有了这个背景知识,我们可以从Entry point address出发,分析该ELF文件的执行过程。

tar xvf glibc-2.35.tar
vim .//sysdeps/arm/start.S
我们来看看arm平台的入口实现:

_start:
       /* Protect against unhandled exceptions.  */
       .fnstart
	/* Clear the frame pointer and link register since this is the outermost frame. */
	/* 清栈帧指针和lr指针,说明这是最外层的栈(FP实际上就是R11寄存器,在APCS调用规则中,使用R11作为帧指针寄存器) */
	mov fp, #0
	mov lr, #0

	/* Pop argc off the stack and save a pointer to argv */
	/* a2 a3代表的是x2 x3寄存器,代表的是传参argc和argv */
	pop { a2 }
	mov a3, sp

	/* Push stack limit a3保存的argv参数指针压栈 */
	push { a3 }

	/* Push rtld_fini 压栈rtld函数*/
	push { a1 }

#ifdef PIC  /* 编译时候加-fPIC参数 PIC就是position independent code  地址无关代码 PIC使.so文件的代码段变为真正意义上的共享库 */
	ldr sl, .L_GOT       /* 加载GOT表 */
	adr a4, .L_GOT
	add sl, sl, a4

	mov a4, #0		/* Used to be init.  */
	push { a4 }		/* Used to be fini.  */

	ldr a1, .L_GOT+4	/* main */
	ldr a1, [sl, a1]

	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */
	/* Let the libc call main and exit with its return code.  */
	bl __libc_start_main(PLT)
#else

	mov a4, #0		/* Used to init.  */
	push { a4 }		/* Used to fini.  */
	ldr a1, =main  /* 这就是我们常说的main是入口函数由来 */

	/* __libc_start_main (main, argc, argv, init, fini, rtld_fini, stack_end) */
	/*实际上前面对于a1 a2 a3的操作都成为了__libc_start_main的入参;
	* a1 = main使我们要执行的函数入口
	* a2/a3是包含环境变量的传参
	* a4 = init是加载main之前的一些初始化工作
	* a5 = fini是main结束之后的收尾工作
	* a6 = rtld_fini是动态加载器的收尾工作
	* a7 = stack_end标明了栈底的地址,即最高的栈地址
	*/
	/* Let the libc call main and exit with its return code.  */
	bl __libc_start_main 
	 /*跳转执行,这个函数就完整了我们整个程序的运行,
	* 其实主要功能就是:__libc_start_main这个函数完成了运行环境的初始化,然后再调用了我们函数中的main,
	* 执行完成后,使用exit函数结束程序。finit用的函数注册在了exit函数中,所以调用exit会执行finit的过程。
	* 到此我们就明白了运行时库是如何帮助我们初始化运行环境,并执行我们的函数,然后退出的过程
	* */
#endif

	/* should never get here....*/
	bl abort

#ifdef PIC
	.align 2
.L_GOT:
	.word _GLOBAL_OFFSET_TABLE_ - .L_GOT
	.word main(GOT)
#endif

       .cantunwind
       .fnend

C语言运行库

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: sldebug 是一个用于调试 Linux 内核模块的工具。如果它一直卡在初始化阶段,可能是因为它无法正常连接到内核。你可以尝试以下步骤解决这个问题: 1. 确认 sldebug 是否支持你当前使用的内核版本。你可以查看 sldebug 的官方文档或者手册来确认。 2. 确认你的内核配置中是否启用了相关的调试选项,例如 CONFIG_DEBUG_KERNEL 和 CONFIG_KGDB。 3. 检查你的系统是否有足够的权限来访问内核调试接口,例如 /dev/kmem 和 /dev/mem。 4. 尝试重新编译和安装 sldebug。 如果以上步骤都无法解决问题,你可以尝试使用其他的内核调试工具,例如 GDB 或者 SystemTap。 ### 回答2: 当 sldebug 运行后一直处于初始化状态时,可能是因为以下几个原因: 1. 网络连接问题:sldebug 可能需要访问网络资源来进行初始化,如果网络连接不稳定或存在问题,可能会导致初始化过程无法完成。此时,可以尝试检查网络连接是否正常,或者尝试使用其他网络连接来解决问题。 2. 资源加载问题:sldebug 的初始化过程可能依赖于某些资源文件或者配置文件。如果这些文件缺失或者加载失败,就会导致初始化失败。此时,可以检查相关的资源文件是否存在,并确保它们被正确地加载和访问。 3. 硬件要求不满足:sldebug 可能有一些硬件要求,例如硬盘空间、内存大小等。如果你的计算机硬件不满足这些要求,sldebug 可能无法启动或者初始化。在这种情况下,可以尝试升级硬件或者使用更加适合的计算机来运行 sldebug。 4. 软件版本不匹配:sldebug 的初始化过程可能依赖于其他软件或者库的版本。如果这些软件或者库的版本与 sldebug 不兼容,就可能导致初始化失败。在这种情况下,可以尝试升级相关软件或者库的版本,或者使用与 sldebug 兼容的版本。 如果以上方法都无法解决问题,建议向 sldebug 的开发者或者官方技术支持团队寻求帮助,提供详细的错误信息和操作过程,以便他们能够更好地理解和解决问题。 ### 回答3: sldebug是一种调试工具,用于调试软件或应用程序的运行过程。一般来说,当我运行sldebug后,它会立即开始初始化过程。然而,如果sldebug一直在初始化,可能会有几个可能的原因。 首先,可能是因为你的计算机性能较低,无法快速完成初始化过程。这可能是由于计算机硬件过旧或运行过程中存在其他资源密集型任务导致的。此时,你可以尝试关闭其他不必要的程序,以释放资源,或者考虑升级你的计算机硬件。 其次,sldebug可能需要连接到外部服务器或数据库来获取必要的数据。如果服务器或数据库出现问题或连接速度较慢,sldebug的初始化过程可能会受到影响。你可以尝试检查网络连接是否正常,或者尝试连接其他服务器或数据库来解决这个问题。 最后,sldebug自身可能存在BUG或错误,导致初始化过程无法正常完成。在这种情况下,你可以尝试更新或重新安装sldebug,以修复任何潜在的问题。 总之,如果sldebug在运行后一直处于初始化状态,你可以尝试优化计算机性能,检查网络连接,或升级/重新安装sldebug来解决这个问题。如果问题仍然存在,你可以尝试与sldebug的开发者或支持团队联系,以获取进一步的帮助和支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值