LinuxQuestions.org
Visit the LQ Articles and Editorials section
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 12-26-2005, 09:56 PM   #1
snowing
LQ Newbie
 
Registered: Jul 2005
Posts: 26

Rep: Reputation: 15
memcpy or mmap or other problems


I want to implement the partial function of grip's userland exec on linux(x86_64). To implement this, I think I can follow the following step:
1. open /lib/ld.so
2. check ld.so's ELF header.
3. do mmap to read ld.so's text
4. read ld.so's text and data to the space got by mmap
5. get ld.so's entry from e_entry
6. setup the stack(to be realized)
7. jmp mmap address
But I now encountered the problem in step4:"read ld.so's text to the space got by mmap", I find that I can memcpy the first time successfully, but will failed on the following tries, It will report" memcpy: illegal seek error", could you please tell me why? Thank you very much.

And the following is my codes:
#include <elf.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>


#define is_loaded(p) ((p)->p_type == PT_LOAD ? 1 : 0)
#define is_txt_segt(p) ((is_loaded(p)) && (p)->p_flags == (PF_X|PF_R))
#define is_data_segt(p) ((is_loaded(p)) && (p)->p_flags == (PF_W|PF_R))

#define FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)

#define ALIGN(k, v) (((k)+((v)-1))&(~((v)-1)))

#define jmp_addr(addr) asm("\tjmp *%0\n" :: "r" (addr))

void * global_ptr = NULL;
void * global_base = NULL;

static Elf64_Ehdr *
load_elf_buf(void *elf_buf)
{
Elf64_Ehdr *e = (Elf64_Ehdr *) elf_buf;
Elf64_Phdr *ptab = (Elf64_Phdr *) ((char *)elf_buf + e->e_phoff);
Elf64_Phdr *p;
size_t tot_len = 0;
void * ptr, * base = NULL;
int i, flags;

/* we could use e->e_type, but this way reduces our code requirement */
for (i = 0, p = ptab; i < e->e_phnum; i++, p++) {
if (!is_loaded(p))
continue;
if (is_txt_segt(p)) {
base = (void *)p->p_vaddr;
global_base = (void *)base;
printf("%d: the address %ld\n", i, (void *)base);
}
tot_len += ALIGN(p->p_memsz, p->p_align);
}

flags = base ? (FLAGS|MAP_FIXED) : FLAGS;

if ((ptr = mmap(base, tot_len, PROT_NONE, flags, -1, 0)) == MAP_FAILED)
return NULL;

global_ptr = (void *)ptr;
for (i = 0, p = ptab; i < e->e_phnum; i++, p++) {
void * load_addr;
size_t len;

if (!is_loaded(p))
continue;

flags = 0;

/* to reduce the code size we could rely on the fact that in
* implementation, the PF_ flags are the same as PROT_ */
if (p->p_flags & PF_X)
flags |= PROT_EXEC;
if (p->p_flags & PF_W)
flags |= PROT_WRITE;
if (p->p_flags & PF_R)
flags |= PROT_READ;

/* a very ugly way of figuring out what the base load address
* of this segment is. */
load_addr = ptr + (((void *)p->p_vaddr-base)&~(p->p_align-1));
len = ALIGN(p->p_memsz, p->p_align);

if (mprotect(load_addr, len, PROT_WRITE)) {
munmap(p, tot_len);
perror("mprotect(PROT_WRITE): ");
return (NULL);
}

/* We need the exact load address, not the rounded down
* version. Otherwis we copy to a garbage location.. */
memcpy((void *)(ptr + ((void *)p->p_vaddr - base)), (void *)elf_buf + p->p_offset, p->p_filesz);
perror("memcpy: ");
printf("%d: the address %ld\n", i, (void *)p->p_vaddr);

if (mprotect(load_addr, len, flags)) {
munmap(p, tot_len);
perror("mprotect(flags): ");
return NULL;
}
}

e = (Elf64_Ehdr *) ptr;

return (e);
}

int main()
{
int fd = -1;
char origld[256] = "/lib64/ld-linux-x86-64.so.2";
Elf64_Ehdr *ehdr = NULL;
Elf64_Phdr *phdr = NULL;
Elf64_Ehdr *e = NULL;
void (*entry)();
struct stat stat;

//system("/lib64/ld-linux-x86-64.so.2 ./hello");

fd = open(origld, O_RDONLY);
if (fd == -1) {
perror("fd open: ");
goto err;
}

if (fstat(fd, &stat) == -1) {
perror("fstat");
goto err;
}

ehdr = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (ehdr == MAP_FAILED) {
perror("mmap ehdr");
goto err;
}
/* Check ELF magic-ident */
if (ehdr->e_ident[EI_MAG0] != 0x7f
|| ehdr->e_ident[EI_MAG1] != 'E'
|| ehdr->e_ident[EI_MAG2] != 'L'
|| ehdr->e_ident[EI_MAG3] != 'F'
) {
fprintf(stderr, "File type not supported\n");
goto err;
}

/* load the dynamic linker */
if ((e = load_elf_buf(ehdr)) == NULL) {
fprintf(stderr, "Can not load elf \n");
goto err;
}
//entry = (void(*)())(ehdr->e_entry + (unsigned long long)(global_ptr - global_base));
entry = (void(*)())ehdr->e_entry;

/* TODO : setup the stack */

/* transfer control to the new image */
jmp_addr(entry);

err:
if (ehdr) {
munmap(ehdr, stat.st_size);
}
if (fd != -1) {
close(fd);
}

}

Last edited by snowing; 12-26-2005 at 09:58 PM.
 
Old 12-26-2005, 11:26 PM   #2
paulsm4
Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
I presume it was an accident that you double-posted (I've done that myself).

But why are you trying to reproduce what the operating system's dynamic linker, dl, already does for you?
 
Old 12-26-2005, 11:38 PM   #3
snowing
LQ Newbie
 
Registered: Jul 2005
Posts: 26

Original Poster
Rep: Reputation: 15
excuse me, but I don't know what does the "double-posted" mean? could you please explain the problem in details? Thank you. I am trying to reproduce what the operating system's dynamic linker to do some work to load the program and glibc ld using large pages.
 
Old 12-26-2005, 11:49 PM   #4
snowing
LQ Newbie
 
Registered: Jul 2005
Posts: 26

Original Poster
Rep: Reputation: 15
Well, I see now. But... how to delete the other posted thread?
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
memcpy or mmap or other problems snowing Programming 0 12-26-2005 09:56 PM
how can i speed up memcpy? Thinking Programming 9 10-14-2005 07:53 AM
memcpy problems alaios Programming 4 09-17-2005 07:26 AM
Need help: Seg fault, Memcpy, and dynamically allocated arrays benobi Programming 3 06-09-2005 10:58 PM
using mmap AngryLlama Programming 1 02-09-2005 08:53 AM


All times are GMT -5. The time now is 09:58 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration