fastcgi 更改环境变量environ引起的段错误(五)glibc的入口函数和环境变量

存放环境变量的 glibc 可执行文件的全局变量 char ** __environ 或者 char **(environ) 在函数__libc_start_main() 中赋值。

文件 glibc-2.32/sysdeps/arm/start.S 定义的函数 _start 的主要作用是设置栈,并调用函数__libc_start_main 设置环境变量 __environ:

环境变量 __environ 位于进程的栈空间,下图是环境变量 __environ 在栈中的位置:

存放环境变量全局变量 char ** __environ 与其它全局变量一样,只在本进程的内存地址空间有效,与另一个进程中的全局变量 char ** __environ 无关。

将下面的代码存放到文件  getenv.c 中:

#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>

#define gettid() syscall(__NR_gettid)

static char * getenv_mxl (const char *name)
{
  size_t len = strlen (name);
  char **ep;
  uint16_t name_start;

  if (__environ == NULL || name[0] == '\0')
    return NULL;

  if (name[1] == '\0')
    {
      /* The name of the variable consists of only one character.  Therefore
	 the first two characters of the environment entry are this character
	 and a '=' character.  */
#if __BYTE_ORDER == __LITTLE_ENDIAN || !_STRING_ARCH_unaligned
      name_start = ('=' << 8) | *(const unsigned char *) name;
#else
      name_start = '=' | ((*(const unsigned char *) name) << 8);
#endif
      for (ep = __environ; *ep != NULL; ++ep)
	{
#if _STRING_ARCH_unaligned
	  uint16_t ep_start = *(uint16_t *) *ep;
#else
	  uint16_t ep_start = (((unsigned char *) *ep)[0]
			       | (((unsigned char *) *ep)[1] << 8));
#endif
	  if (name_start == ep_start)
	    return &(*ep)[2];
	}
    }
  else
    {
#if _STRING_ARCH_unaligned
      name_start = *(const uint16_t *) name;
#else
      name_start = (((const unsigned char *) name)[0]
		    | (((const unsigned char *) name)[1] << 8));
#endif
      len -= 2;
      name += 2;

      for (ep = __environ; *ep != NULL; ++ep)
	{
#if _STRING_ARCH_unaligned
	  uint16_t ep_start = *(uint16_t *) *ep;
#else
	  uint16_t ep_start = (((unsigned char *) *ep)[0]
			       | (((unsigned char *) *ep)[1] << 8));
#endif

	  if (name_start == ep_start && !strncmp (*ep + 2, name, len)
	      && (*ep)[len + 2] == '=')
	    return &(*ep)[len + 3];
	}
    }

  return NULL;
}

void main(void)
{
    char **ep;
    char *cp ;
    printf("__environ = %p.\n", __environ);
    for (ep = __environ; *ep != NULL; ++ep)
    {
        printf("address of ep= %p , ep = %s\n", ep, *ep);
    }

    while(1)
    {
      printf("%s :  I am thread ID: LWPID = %ld.\n", __FUNCTION__, (long int)gettid());
      printf("__environ = %p.\n", __environ);
      for (ep = __environ; *ep != NULL; ++ep)
      {
          printf("address of ep= %p , ep = %s\n", ep, *ep);
      }      
      cp = getenv_mxl("LOCALDOMAIN");
      if( cp == NULL)
          perror("get LOCALDOMAIN error:");
      else
        printf("env LOCALDOMAIN = %s.\n", cp);
      sleep(10);
      printf("******************************************\n");
    }
}

使用  arm32 架构的 RK3128 的工具链编译成可执行文件getenv_unset,并在 rk3128 上执行,左边的窗口设置环境变量 export mxl=linfen,其全局变量 char ** __environ 的地址为 0xbeb5ddbc ,右边的窗口设置环境变量 export linfen=mxl,其全局变量 char ** __environ 的地址为 0xbeabcdbc

参见《程序员的自我修养》:

glibc可执行文件的入口函数并不是 main,对于arm平台,glibc可执行文件的入口函数是文件 glibc-2.32/sysdeps/arm/start.S 定义的函数 _start ,参见《程序员的自我修养》:

文件 glibc-2.32/sysdeps/arm/start.S 定义的函数 _start 的主要作用是设置栈,并调用函数__libc_start_main 设置环境变量 __environ:

环境变量 __environ 位于进程的栈空间,下图是环境变量 __environ 在栈中的位置:

文件 文件 glibc-2.32/sysdeps/arm/start.S 的实现如下:

/* Startup code for ARM & ELF */

/* This is the canonical entry point, usually the first thing in the text  segment.

	Note that the code in the .init section has already been run.
	This includes _init and _libc_init
	At this entry point, most registers' values are unspecified, except:
   a1		Contains a function pointer to be registered with `atexit'.
		This is how the dynamic linker arranges to have DT_FINI
		functions called for shared libraries that have been loaded
		before this code runs.

   sp		The stack contains the arguments and environment:
		0(sp)			argc
		4(sp)			argv[0]
		...
		(4*argc)(sp)		NULL
		(4*(argc+1))(sp)	envp[0]
		...
					NULL
*/

	.text
	.globl _start
	.type _start,#function
_start:
    /* Protect against unhandled exceptions.  */
    .fnstart
	/* Clear the frame pointer and link register since this is the outermost frame. */
	mov fp, #0
	mov lr, #0

	/* Pop argc off the stack and save a pointer to argv */
	pop { a2 }
	mov a3, sp

	/* Push stack limit */
	push { a3 }

	/* Push rtld_fini */
	push { a1 }

	/* Fetch address of __libc_csu_fini */
	ldr ip, =__libc_csu_fini
//glibc-2.32/csu/elf-init.c
void __libc_csu_init (int argc, char **argv, char **envp)
{
  /* For dynamically linked executables the preinit array is executed by
     the dynamic linker (before initializing any shared object).  */
  const size_t size = __init_array_end - __init_array_start;
  for (size_t i = 0; i < size; i++)
      (*__init_array_start [i]) (argc, argv, envp);
}

	/* Push __libc_csu_fini */
	push { ip }

	/* Set up the other arguments in registers */
	ldr a1, =main
	ldr a4, =__libc_csu_init

	/* __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
//glibc-2.32/csu/libc-start.c
/* Note: the fini parameter is ignored here for shared library.  It
   is registered with __cxa_atexit.  This had the disadvantage that
   finalizers were called in more than one place.  */
STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
		 int argc, char **argv,
		 __typeof (main) init,
		 void (*fini) (void),
		 void (*rtld_fini) (void), void *stack_end)
{
  /* Initialize very early so that tunables can use it.  */
  __libc_init_secure ();
  __tunables_init (__environ)->	//初始环境变量
	char **prev_envp = __environ;
	while ((envp = get_next_env (envp, &envname, &len, &envval, &prev_envp)) != NULL)
	{
		char *new_env = tunables_strdup (envname);
		if (new_env != NULL)
			parse_tunables (new_env + len + 1, envval);
		/* Put in the updated envval.  */
		*prev_envp = new_env;

		for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
		{
			tunable_t *cur = &tunable_list[i];
			const char *name = cur->env_alias;
			if (__libc_enable_secure)
			{
				 /* Erase the environment variable.  */
				char **ep = prev_envp;
				envp = prev_envp;
			}
			tunable_initialize (cur, envval);
			break;
		}
	}
	if (init)
		(*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
	result = main (argc, argv, __environ MAIN_AUXVEC_PARAM);

 glibc可执行文件反汇编观察入口函数

将下面的代码保存在文件 function_entry.c 中:

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char*argv)

{

    printf("test glibc function entry.\n");

    return 0;

}

使用  arm32 架构的 RK3128 的工具链编译成可执行文件,再使用 objdump -S 命令反汇编可执行文件 function_entry,输出结果如下,可以看出入口函数是 _start :

function_entry:     file format elf32-littlearm


Disassembly of section .init:

000102c8 <_init>:
   102c8:	e92d4008 	push	{r3, lr}
   102cc:	eb000020 	bl	10354 <call_weak_fn>
   102d0:	e8bd8008 	pop	{r3, pc}

Disassembly of section .plt:

000102d4 <.plt>:
   102d4:	e52de004 	push	{lr}		; (str lr, [sp, #-4]!)
   102d8:	e59fe004 	ldr	lr, [pc, #4]	; 102e4 <.plt+0x10>
   102dc:	e08fe00e 	add	lr, pc, lr
   102e0:	e5bef008 	ldr	pc, [lr, #8]!
   102e4:	00010d1c 	.word	0x00010d1c

000102e8 <puts@plt>:
   102e8:	e28fc600 	add	ip, pc, #0, 12
   102ec:	e28cca10 	add	ip, ip, #16, 20	; 0x10000
   102f0:	e5bcfd1c 	ldr	pc, [ip, #3356]!	; 0xd1c

000102f4 <__libc_start_main@plt>:
   102f4:	e28fc600 	add	ip, pc, #0, 12
   102f8:	e28cca10 	add	ip, ip, #16, 20	; 0x10000
   102fc:	e5bcfd14 	ldr	pc, [ip, #3348]!	; 0xd14

00010300 <__gmon_start__@plt>:
   10300:	e28fc600 	add	ip, pc, #0, 12
   10304:	e28cca10 	add	ip, ip, #16, 20	; 0x10000
   10308:	e5bcfd0c 	ldr	pc, [ip, #3340]!	; 0xd0c

0001030c <abort@plt>:
   1030c:	e28fc600 	add	ip, pc, #0, 12
   10310:	e28cca10 	add	ip, ip, #16, 20	; 0x10000
   10314:	e5bcfd04 	ldr	pc, [ip, #3332]!	; 0xd04

Disassembly of section .text:

00010318 <_start>:
   10318:	e3a0b000 	mov	fp, #0
   1031c:	e3a0e000 	mov	lr, #0
   10320:	e49d1004 	pop	{r1}		; (ldr r1, [sp], #4)
   10324:	e1a0200d 	mov	r2, sp
   10328:	e52d2004 	push	{r2}		; (str r2, [sp, #-4]!)
   1032c:	e52d0004 	push	{r0}		; (str r0, [sp, #-4]!)
   10330:	e59fc010 	ldr	ip, [pc, #16]	; 10348 <_start+0x30>
   10334:	e52dc004 	push	{ip}		; (str ip, [sp, #-4]!)
   10338:	e59f000c 	ldr	r0, [pc, #12]	; 1034c <_start+0x34>
   1033c:	e59f300c 	ldr	r3, [pc, #12]	; 10350 <_start+0x38>
   10340:	ebffffeb 	bl	102f4 <__libc_start_main@plt>
   10344:	ebfffff0 	bl	1030c <abort@plt>
   10348:	0001049c 	.word	0x0001049c
   1034c:	00010408 	.word	0x00010408
   10350:	00010438 	.word	0x00010438

00010354 <call_weak_fn>:
   10354:	e59f3014 	ldr	r3, [pc, #20]	; 10370 <call_weak_fn+0x1c>
   10358:	e59f2014 	ldr	r2, [pc, #20]	; 10374 <call_weak_fn+0x20>
   1035c:	e08f3003 	add	r3, pc, r3
   10360:	e7932002 	ldr	r2, [r3, r2]
   10364:	e3520000 	cmp	r2, #0
   10368:	012fff1e 	bxeq	lr
   1036c:	eaffffe3 	b	10300 <__gmon_start__@plt>
   10370:	00010c9c 	.word	0x00010c9c
   10374:	0000001c 	.word	0x0000001c

00010378 <deregister_tm_clones>:
   10378:	e59f0018 	ldr	r0, [pc, #24]	; 10398 <deregister_tm_clones+0x20>
   1037c:	e59f3018 	ldr	r3, [pc, #24]	; 1039c <deregister_tm_clones+0x24>
   10380:	e1530000 	cmp	r3, r0
   10384:	012fff1e 	bxeq	lr
   10388:	e59f3010 	ldr	r3, [pc, #16]	; 103a0 <deregister_tm_clones+0x28>
   1038c:	e3530000 	cmp	r3, #0
   10390:	012fff1e 	bxeq	lr
   10394:	e12fff13 	bx	r3
   10398:	00021028 	.word	0x00021028
   1039c:	00021028 	.word	0x00021028
   103a0:	00000000 	.word	0x00000000

000103a4 <register_tm_clones>:
   103a4:	e59f0024 	ldr	r0, [pc, #36]	; 103d0 <register_tm_clones+0x2c>
   103a8:	e59f1024 	ldr	r1, [pc, #36]	; 103d4 <register_tm_clones+0x30>
   103ac:	e0413000 	sub	r3, r1, r0
   103b0:	e1a01fa3 	lsr	r1, r3, #31
   103b4:	e0811143 	add	r1, r1, r3, asr #2
   103b8:	e1b010c1 	asrs	r1, r1, #1
   103bc:	012fff1e 	bxeq	lr
   103c0:	e59f3010 	ldr	r3, [pc, #16]	; 103d8 <register_tm_clones+0x34>
   103c4:	e3530000 	cmp	r3, #0
   103c8:	012fff1e 	bxeq	lr
   103cc:	e12fff13 	bx	r3
   103d0:	00021028 	.word	0x00021028
   103d4:	00021028 	.word	0x00021028
   103d8:	00000000 	.word	0x00000000

000103dc <__do_global_dtors_aux>:
   103dc:	e92d4010 	push	{r4, lr}
   103e0:	e59f4018 	ldr	r4, [pc, #24]	; 10400 <__do_global_dtors_aux+0x24>
   103e4:	e5d43000 	ldrb	r3, [r4]
   103e8:	e3530000 	cmp	r3, #0
   103ec:	18bd8010 	popne	{r4, pc}
   103f0:	ebffffe0 	bl	10378 <deregister_tm_clones>
   103f4:	e3a03001 	mov	r3, #1
   103f8:	e5c43000 	strb	r3, [r4]
   103fc:	e8bd8010 	pop	{r4, pc}
   10400:	00021028 	.word	0x00021028

00010404 <frame_dummy>:
   10404:	eaffffe6 	b	103a4 <register_tm_clones>

00010408 <main>:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char*argv)
{
   10408:	e92d4800 	push	{fp, lr}
   1040c:	e28db004 	add	fp, sp, #4
   10410:	e24dd008 	sub	sp, sp, #8
   10414:	e50b0008 	str	r0, [fp, #-8]
   10418:	e50b100c 	str	r1, [fp, #-12]
    printf("test glibc function entry.\n");
   1041c:	e300053c 	movw	r0, #1340	; 0x53c
   10420:	e3400001 	movt	r0, #1
   10424:	ebffffaf 	bl	102e8 <puts@plt>
    return 0;
   10428:	e3a03000 	mov	r3, #0
   1042c:	e1a00003 	mov	r0, r3
   10430:	e24bd004 	sub	sp, fp, #4
   10434:	e8bd8800 	pop	{fp, pc}

00010438 <__libc_csu_init>:
   10438:	e92d47f0 	push	{r4, r5, r6, r7, r8, r9, sl, lr}
   1043c:	e1a07000 	mov	r7, r0
   10440:	e59f604c 	ldr	r6, [pc, #76]	; 10494 <__libc_csu_init+0x5c>
   10444:	e1a08001 	mov	r8, r1
   10448:	e59f5048 	ldr	r5, [pc, #72]	; 10498 <__libc_csu_init+0x60>
   1044c:	e1a09002 	mov	r9, r2
   10450:	e08f6006 	add	r6, pc, r6
   10454:	ebffff9b 	bl	102c8 <_init>
   10458:	e08f5005 	add	r5, pc, r5
   1045c:	e0466005 	sub	r6, r6, r5
   10460:	e1b06146 	asrs	r6, r6, #2
   10464:	08bd87f0 	popeq	{r4, r5, r6, r7, r8, r9, sl, pc}
   10468:	e2455004 	sub	r5, r5, #4
   1046c:	e3a04000 	mov	r4, #0
   10470:	e5b53004 	ldr	r3, [r5, #4]!
   10474:	e1a02009 	mov	r2, r9
   10478:	e1a01008 	mov	r1, r8
   1047c:	e1a00007 	mov	r0, r7
   10480:	e2844001 	add	r4, r4, #1
   10484:	e12fff33 	blx	r3
   10488:	e1560004 	cmp	r6, r4
   1048c:	1afffff7 	bne	10470 <__libc_csu_init+0x38>
   10490:	e8bd87f0 	pop	{r4, r5, r6, r7, r8, r9, sl, pc}
   10494:	00010ab4 	.word	0x00010ab4
   10498:	00010aa8 	.word	0x00010aa8

0001049c <__libc_csu_fini>:
   1049c:	e12fff1e 	bx	lr

Disassembly of section .fini:

000104a0 <_fini>:
   104a0:	e92d4008 	push	{r3, lr}
   104a4:	e8bd8008 	pop	{r3, pc}

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值