Help with libc implementation

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Help with libc implementation

Post by mohammedisam »

Hi again :D

So, I got so far to have a running cross-compiler. I tried compiling an ELF executable that prints a simple "Hello World" string using my libc printf function, which in turn calls the respective syscall to do the writing. It seemingly compiled error-free, so I copied it to my virtual disk and tried running it. The module loads correctly into memory (entry at 0x08048090 as indicated in the file header), all ELF header checks passed, I switch to user mode, and execution starts, but a few instructions down the road, it page faults. I dumpobj'd the executable and traced it. _start goes on and calls init_std_library which currently does nothing (I didn't implement the memory-environ-argc-argv stuff yet), then _init is called. Here _init calls __do_global_ctors_aux, which (as I understand) should traverse a list of global constructors and call them. Okay, the problem is that the list is empty (not *empty*, but contains ffffff followed by 00). The .ctors section shows:

Code: Select all

Disassembly of section .ctors:

080493a8 <__CTOR_LIST__>:
 80493a8:	ff                   	(bad)  
 80493a9:	ff                   	(bad)  
 80493aa:	ff                   	(bad)  
 80493ab:	ff 00                	incl   (%eax)

080493ac <__CTOR_END__>:
 80493ac:	00 00                	add    %al,(%eax)
	...
After looking at __do_global_ctors_aux, it looks that it loads the first item in the list, compares it to 0xffffffff (which turns true) and then bails out and returns.

Code: Select all

080482b0 <__do_global_ctors_aux>:
 80482b0:	55                   	        push   %ebp
 80482b1:	89 e5                	mov    %esp,%ebp
 80482b3:	53                   	        push   %ebx
 80482b4:	bb a8 93 04 08       	mov    $0x80493a8,%ebx
 80482b9:	83 ec 04             	sub    $0x4,%esp
 80482bc:	a1 a8 93 04 08       	mov    0x80493a8,%eax             <<<<< This is the address of the first item in the .ctors list
 80482c1:	83 f8 ff             	        cmp    $0xffffffff,%eax
 80482c4:	74 16                	je     80482dc <__do_global_ctors_aux+0x2c>
 80482c6:	8d 76 00             	lea    0x0(%esi),%esi
 80482c9:	8d bc 27 00 00 00 00 	lea    0x0(%edi,%eiz,1),%edi
 80482d0:	83 eb 04             	sub    $0x4,%ebx
 80482d3:	ff d0                	        call   *%eax
 80482d5:	8b 03                	mov    (%ebx),%eax
 80482d7:	83 f8 ff               	cmp    $0xffffffff,%eax
 80482da:	75 f4                	        jne    80482d0 <__do_global_ctors_aux+0x20>
 80482dc:	83 c4 04             	add    $0x4,%esp
 80482df:	5b                      	pop    %ebx                                     <<<<<< bails out
 80482e0:	5d                     	pop    %ebp
 80482e1:	c3                     	ret    
When it returns, execution goes to 0x08048081, the instruction at which tries to access the address saved in %eax (currently0xffffffff) which of course is not mapped to the user process, hence the page fault. Furthermore, i don't know where this address came from, as it is absent from the dump:

Code: Select all

....
 804807c:	e8 2f 02 00 00       	call   80482b0 <__do_global_ctors_aux>
******* NOTHING in between these addresses!!! *******
Disassembly of section .text:

08048090 <_start>:
....
I read the Wiki on "Calling global constructors" & "Creating C library" but they doesn't say much about the global constructors. I spent hours googling it (to no avail). I looked into the GNU libc source, but it is too much twisted and full of macros that it is very hard to decipher :( .

So, I guess my questions are:
[1] How can I define (or for the moment, while running simple programs, skip) the global constructors? In other words, how can I change (or edit) the list of ctors used by the cross compiler when cross compiling my code using my libc?
[2] Is there any specific standard for what items to push on the stack before invoking the executable (I know I need to push a pointer to argv, environmental variables, argc, anything else *essential* for a simple "Hello World" program to run)?
[3] Any good sources on implementing the standard C library? I've read the ISO standard which gave me a good insight but it's rather theoretical, and the crt* stuff is not included in the standard. I am reading "The Standard C Library" by P.J. Plaucer currently. Any other practical sources?

Thanx :D
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Help with libc implementation

Post by alexfru »

You could try mine.
include/*.h
srclib/*.c
doc
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Help with libc implementation

Post by sortie »

What libc are you using? Your own? How are you compiling the libc sources? How are you compiling and linking the user program? Are you using a OS Specific Toolchain?
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Re: Help with libc implementation

Post by mohammedisam »

alexfru wrote:You could try mine.
include/*.h
srclib/*.c
doc
Great! I will look into it.
Thanx a lot alexfru =D>
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Re: Help with libc implementation

Post by mohammedisam »

sortie wrote:What libc are you using? Your own? How are you compiling the libc sources? How are you compiling and linking the user program? Are you using a OS Specific Toolchain?
Yes I am using my own libc. I created stub headers as defined in the "Hosted GCC Cross Compiler" tutorial's link http://pastebin.com/0dwhXNPC. I am compiling using the OS specific toolchain.
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Help with libc implementation

Post by sortie »

Sounds good. You forgot to answer:
mohammedisam wrote:How are you compiling and linking the user program?
Your ELF program loader uses the Program Headers, right? (And not the section headers.)

(I'm sanity checking your environment right now. Your problem sounds quite odd.)

Hm. Reading your post more careful, I'm a bit confused. I'm not sure you're describing in enough detail what is happening. Perhaps your code is somehow falling out the end of a function if it ends up executing garbage, or perhaps the program wasn't loaded properly. I'll have to re-read it when I'm a bit more clear-thinking. It's worth tripple-checking (and then another seven times to be sure) that your interrupt/syscall handlers provably doesn't corrupt registers of that which they executed. Also be sure you follow all the applicable ABI requirement. All that kind of things that must be correct or weird stuff happens. I realize I'm not being of much use here.

As for your original questions:

I suggest you don't skip running the global constructors. A weird problem occurs, you definitely want to find out what it is, otherwise it's likely it'll just come back in another form.

The System V ABI defines a bit of the state when _start is invoked. However, it really doesn't matter, as you can do anything you want as long as the program loader and _start function agree on a protocol. Nobody else is going to do a _start for your OS anyways, unless you port weird stuff (think wine or another programming language?) where you'll need to adapt stuff anyway.

There is another new thread How to best implement your own C library you might like to read.
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Re: Help with libc implementation

Post by mohammedisam »

sortie wrote:Sounds good. You forgot to answer:
sortie wrote:How are you compiling and linking the user program?
I am using:

Code: Select all

i686-detour-gcc -static -o test test.c
When I objdump the resulting executable, I see

Code: Select all

08048079 <_init>:
.section .init
.global _init
.type _init, @function

_init:
  push %ebp
 8048079:	55                   	push   %ebp
  movl %esp, %ebp
 804807a:	89 e5                	mov    %esp,%ebp
 804807c:	e8 0f 03 00 00       	call   8048390 <__do_global_ctors_aux>

Disassembly of section .text:

08048090 <_start>:
Correct me if I am wrong: shouldn't there be a ret instruction at the end of _init? So that it will return control to _start?
sortie wrote:Your ELF program loader uses the Program Headers, right? (And not the section headers.)
Here is my elf loading function:

Code: Select all

task_t elf_load_exec(char *file, elf32_ehdr *hdr)
{
  task_t task;
  uint32_t image_size = 0;
  uint32_t base_addr = 0;
  
  uint32_t phys;
  int pages_used = 0;
  uint32_t stack = 0;
  
  elf32_phdr *phdr = (elf32_phdr *)&file[hdr->e_phoff];
  for(int i = 0; i < hdr->e_phnum; i++)
  {
    if(phdr[i].p_type == PT_LOAD)
    {
      printf("Loading segment #%u/%u\n", i, hdr->e_phnum);
      uint32_t memsize = phdr[i].p_memsz;
      uint32_t filesize = phdr[i].p_filesz;
      uint32_t mempos = phdr[i].p_vaddr;
      uint32_t filepos = phdr[i].p_offset;
      
      for(uint32_t z = mempos; z < mempos+memsize; z += 0x1000, phys += 0x1000)
      {
 	phys = first_frame()*0x1000;
	 set_frame(phys);
 	map_virt_to_phys(z, phys);
 	pages_used++;
      }
	__asm__("xchg %%bx, %%bx"::);
      memset((void *)mempos, 0, memsize);
      memcpy((void *)mempos, (file+filepos), filesize);
      //zero out the rest of the image space in memory
      if(filesize < memsize)
	 memset((void *)(mempos+filesize), 0, memsize-filesize);
      
      uint32_t new_stack = mempos+(pages_used*0x1000);
      int rest = new_stack % 0x1000;
      new_stack += (0x1000-rest);
      
      image_size += memsize;
      if(stack == 0) stack = new_stack;
      
      if(base_addr == 0 || base_addr > mempos)
 	base_addr = mempos;
      else stack = new_stack;
    }
  }
  
  __asm__("xchg %%bx, %%bx"::);
  for(uint32_t z = stack; z < stack+0x2000; z += 0x1000)
  {
    phys = first_frame()*0x1000;
    set_frame(phys);
    map_virt_to_phys(z, phys);
    memset((void *)z, 0, 0x1000);
  }
  task.esp = (uint32_t)(stack+PAGE_SIZE-1);
  task.ebp = (uint32_t)(stack+PAGE_SIZE-1);
  
  task.eip = hdr->e_entry;
  task.pid = 1;		//temporary, will change it later
  task.image_base = base_addr;
  task.image_size = image_size;
  return task;
}
sortie wrote:There is another new thread How to best implement your own C library you might like to read.
I am looking at your libc files, it looks interesting.
I hope this helps clarify my standing. Thanx 4 ur input. :D
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Re: Help with libc implementation

Post by mohammedisam »

I got the problem :)

For some reason, gcc doesn't link the crtn.o to the executable. The file contains:

Code: Select all

.section .init
  /* gcc will nicely put the contents of crtend.o's .init section here. */
  popl %ebp
  ret
  
.section .fini
  /* gcc will nicely put the contents of crtend.o's .fini section here. */
  popl %ebp
  ret
Thus when the __do_global_ctors_aux() comes back, it ought to take off from the instruction popl %ebp, then execute ret to the _start function. As the crtn.o is not linked (it's place is zeroed out by the linker earlier), eip points to zeros, the processor interprets it as an instruction and tries to execute it, hence the page fault.

I am oblivious to why gcc is linking crti.o and cr0.o, but not linking crtn.o :shock:
Any how, this is the problem that I figured out after single tracing the execution, but still I donno how to remedy it.
Any ideas??
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Help with libc implementation

Post by sortie »

You probably want to examine your STARTFILES_SPEC and ENDFILES_SPEC.

For the record, see how I do it: https://gitlab.com/sortix/gcc/blob/mast ... g/sortix.h
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Re: Help with libc implementation

Post by mohammedisam »

sortie wrote:You probably want to examine your STARTFILES_SPEC and ENDFILES_SPEC.

For the record, see how I do it: https://gitlab.com/sortix/gcc/blob/mast ... g/sortix.h
Yep. that sure helped. =D>
I recompiled the hosted gcc compiler with the above specs and now crtn.o links correctly.
Thanx a lot sortie :D
Post Reply