/* load program text and initialized data into simulated virtual memory space and initialize program segment range variables */ void ld_load_prog(char *fname, /* program to load */ int argc, char **argv, /* simulated program cmd line args */ char **envp, /* simulated program environment */ struct regs_t *regs, /* registers to initialize for load */ struct mem_t *mem, /* memory space to load prog into */ int zero_bss_segs) /* zero uninit data segment? */ { int i; qword_t temp; md_addr_t sp, data_break = 0, null_ptr = 0, argv_addr, envp_addr; if (eio_valid(fname)) { if (argc != 1) { fprintf(stderr, "error: EIO file has arguments\n"); exit(1); } fprintf(stderr, "sim: loading EIO file: %s\n", fname); sim_eio_fname = mystrdup(fname); /* open the EIO file stream */ sim_eio_fd = eio_open(fname); /* load initial state checkpoint */ if (eio_read_chkpt(regs, mem, sim_eio_fd) != -1) fatal("bad initial checkpoint in EIO file"); /* load checkpoint? */ if (sim_chkpt_fname != NULL) { counter_t restore_icnt; FILE *chkpt_fd; fprintf(stderr, "sim: loading checkpoint file: %s\n", sim_chkpt_fname); if (!eio_valid(sim_chkpt_fname)) fatal("file `%s' does not appear to be a checkpoint file", sim_chkpt_fname); /* open the checkpoint file */ chkpt_fd = eio_open(sim_chkpt_fname); /* load the state image */ restore_icnt = eio_read_chkpt(regs, mem, chkpt_fd); /* fast forward the baseline EIO trace to checkpoint location */ myfprintf(stderr, "sim: fast forwarding to instruction %n\n", restore_icnt); eio_fast_forward(sim_eio_fd, restore_icnt); } /* computed state... */ ld_environ_base = regs->regs_R[MD_REG_SP]; ld_prog_entry = regs->regs_PC; /* fini... */ return; } #ifdef MD_CROSS_ENDIAN else { warn("endian of `%s' does not match host", fname); warn("running with experimental cross-endian execution support"); warn("****************************************"); warn("**>> please check results carefully <<**"); warn("****************************************"); #if 0 fatal("SimpleScalar/Alpha only supports binary execution on\n" " little-endian hosts, use EIO files on big-endian hosts"); #endif } #endif /* MD_CROSS_ENDIAN */ if (sim_chkpt_fname != NULL) fatal("checkpoints only supported while EIO tracing"); #ifdef BFD_LOADER { bfd *abfd; asection *sect; /* set up a local stack pointer, this is where the argv and envp data is written into program memory */ ld_stack_base = MD_STACK_BASE; sp = ROUND_DOWN(MD_STACK_BASE - MD_MAX_ENVIRON, sizeof(MD_DOUBLE_TYPE)); ld_stack_size = ld_stack_base - sp; printf("Thread 0 stack size (3)%d\n", current->ld_stack_size); /* initial stack pointer value */ ld_environ_base = sp; /* load the program into memory, try both endians */ if (!(abfd = bfd_openr(argv[0], "ss-coff-big"))) if (!(abfd = bfd_openr(argv[0], "ss-coff-little"))) fatal("cannot open executable `%s'", argv[0]); /* this call is mainly for its side effect of reading in the sections. we follow the traditional behavior of `strings' in that we don't complain if we don't recognize a file to be an object file. */ if (!bfd_check_format(abfd, bfd_object)) { bfd_close(abfd); fatal("cannot open executable `%s'", argv[0]); } /* record profile file name */ ld_prog_fname = argv[0]; /* record endian of target */ ld_target_big_endian = abfd->xvec->byteorder_big_p; debug("processing %d sections in `%s'...", bfd_count_sections(abfd), argv[0]); /* read all sections in file */ for (sect=abfd->sections; sect; sect=sect->next) { char *p; debug("processing section `%s', %d bytes @ 0x%08x...", bfd_section_name(abfd, sect), bfd_section_size(abfd, sect), bfd_section_vma(abfd, sect)); /* read the section data, if allocated and loadable and non-NULL */ if ((bfd_get_section_flags(abfd, sect) & SEC_ALLOC) && (bfd_get_section_flags(abfd, sect) & SEC_LOAD) && bfd_section_vma(abfd, sect) && bfd_section_size(abfd, sect)) { /* allocate a section buffer */ p = calloc(bfd_section_size(abfd, sect), sizeof(char)); if (!p) fatal("cannot allocate %d bytes for section `%s'", bfd_section_size(abfd, sect), bfd_section_name(abfd, sect)); if (!bfd_get_section_contents(abfd, sect, p, (file_ptr)0, bfd_section_size(abfd, sect))) fatal("could not read entire `%s' section from executable", bfd_section_name(abfd, sect)); /* copy program section it into simulator target memory */ mem_bcopy(mem_fn, Write, bfd_section_vma(abfd, sect), p, bfd_section_size(abfd, sect)); /* release the section buffer */ free(p); } /* zero out the section if it is loadable but not allocated in exec */ else if (zero_bss_segs && (bfd_get_section_flags(abfd, sect) & SEC_LOAD) && bfd_section_vma(abfd, sect) && bfd_section_size(abfd, sect)) { /* zero out the section region */ mem_bzero(mem_fn, bfd_section_vma(abfd, sect), bfd_section_size(abfd, sect)); } else { /* else do nothing with this section, it's probably debug data */ debug("ignoring section `%s' during load...", bfd_section_name(abfd, sect)); } /* expected text section */ if (!strcmp(bfd_section_name(abfd, sect), ".text")) { /* .text section processing */ ld_text_size = ((bfd_section_vma(abfd, sect) + bfd_section_size(abfd, sect)) - MD_TEXT_BASE) + /* for speculative fetches/decodes */TEXT_TAIL_PADDING; /* create tail padding and copy into simulator target memory */ #if 0 mem_bzero(mem_fn, bfd_section_vma(abfd, sect) + bfd_section_size(abfd, sect), TEXT_TAIL_PADDING); #endif } /* expected data sections */ else if (!strcmp(bfd_section_name(abfd, sect), ".rdata") || !strcmp(bfd_section_name(abfd, sect), ".data") || !strcmp(bfd_section_name(abfd, sect), ".sdata") || !strcmp(bfd_section_name(abfd, sect), ".bss") || !strcmp(bfd_section_name(abfd, sect), ".sbss")) { /* data section processing */ if (bfd_section_vma(abfd, sect) + bfd_section_size(abfd, sect) > data_break) data_break = (bfd_section_vma(abfd, sect) + bfd_section_size(abfd, sect)); } else { /* what is this section??? */ fatal("encountered unknown section `%s', %d bytes @ 0x%08x", bfd_section_name(abfd, sect), bfd_section_size(abfd, sect), bfd_section_vma(abfd, sect)); } } /* compute data segment size from data break point */ ld_text_base = MD_TEXT_BASE; ld_data_base = MD_DATA_BASE; ld_prog_entry = bfd_get_start_address(abfd); ld_data_size = data_break - ld_data_base; /* done with the executable, close it */ if (!bfd_close(abfd)) fatal("could not close executable `%s'", argv[0]); } #else /* !BFD_LOADER, i.e., standalone loader */ { FILE *fobj; long floc; struct ecoff_filehdr fhdr; struct ecoff_aouthdr ahdr; struct ecoff_scnhdr shdr; /* record profile file name */ ld_prog_fname = argv[0]; /* load the program into memory, try both endians */ #if defined(__CYGWIN32__) || defined(_MSC_VER) fobj = fopen(argv[0], "rb"); #else fobj = fopen(argv[0], "r"); #endif if (!fobj) fatal("cannot open executable `%s'", argv[0]); if (fread(&fhdr, sizeof(struct ecoff_filehdr), 1, fobj) < 1) fatal("cannot read header from executable `%s'", argv[0]); /* record endian of target */ if (fhdr.f_magic == MD_SWAPH(ECOFF_ALPHAMAGIC)) ld_target_big_endian = FALSE; else if (fhdr.f_magic == MD_SWAPH(ECOFF_EB_MAGIC) || fhdr.f_magic == MD_SWAPH(ECOFF_EL_MAGIC) || fhdr.f_magic == MD_SWAPH(ECOFF_EB_OTHER) || fhdr.f_magic == MD_SWAPH(ECOFF_EL_OTHER)) fatal("Alpha simulator cannot run PISA binary `%s'", argv[0]); else fatal("bad magic number in executable `%s' (not an executable)", argv[0]); if (fread(&ahdr, sizeof(struct ecoff_aouthdr), 1, fobj) < 1) fatal("cannot read AOUT header from executable `%s'", argv[0]); ld_text_base = MD_SWAPQ(ahdr.text_start); ld_text_size = MD_SWAPQ(ahdr.tsize); ld_prog_entry = MD_SWAPQ(ahdr.entry); ld_data_base = MD_SWAPQ(ahdr.data_start); ld_data_size = MD_SWAPQ(ahdr.dsize) + MD_SWAPQ(ahdr.bsize); regs->regs_R[MD_REG_GP] = MD_SWAPQ(ahdr.gp_value); /* compute data segment size from data break point */ data_break = ld_data_base + ld_data_size; /* seek to the beginning of the first section header, the file header comes first, followed by the optional header (this is the aouthdr), the size of the aouthdr is given in Fdhr.f_opthdr */ fseek(fobj, sizeof(struct ecoff_filehdr) + MD_SWAPH(fhdr.f_opthdr), 0); debug("processing %d sections in `%s'...", MD_SWAPH(fhdr.f_nscns), argv[0]); /* loop through the section headers */ floc = ftell(fobj); for (i = 0; i < MD_SWAPH(fhdr.f_nscns); i++) { char *p; if (fseek(fobj, floc, 0) == -1) fatal("could not reset location in executable"); if (fread(&shdr, sizeof(struct ecoff_scnhdr), 1, fobj) < 1) fatal("could not read section %d from executable", i); floc = ftell(fobj); switch (MD_SWAPW(shdr.s_flags)) { case ECOFF_STYP_TEXT: p = calloc(MD_SWAPQ(shdr.s_size), sizeof(char)); if (!p) fatal("out of virtual memory"); if (fseek(fobj, MD_SWAPQ(shdr.s_scnptr), 0) == -1) fatal("could not read `.text' from executable", i); if (fread(p, MD_SWAPQ(shdr.s_size), 1, fobj) < 1) fatal("could not read text section from executable"); /* copy program section into simulator target memory */ mem_bcopy(mem_access, mem, Write, MD_SWAPQ(shdr.s_vaddr), p, MD_SWAPQ(shdr.s_size)); #if 0 /* create tail padding and copy into simulator target memory */ mem_bzero(mem_access, mem, MD_SWAPQ(shdr.s_vaddr) + MD_SWAPQ(shdr.s_size), TEXT_TAIL_PADDING); #endif /* release the section buffer */ free(p); #if 0 Text_seek = MD_SWAPQ(shdr.s_scnptr); Text_start = MD_SWAPQ(shdr.s_vaddr); Text_size = MD_SWAPQ(shdr.s_size) / 4; /* there is a null routine after the supposed end of text */ Text_size += 10; Text_end = Text_start + Text_size * 4; /* create_text_reloc(shdr.s_relptr, shdr.s_nreloc); */ #endif break; case ECOFF_STYP_INIT: case ECOFF_STYP_FINI: if (MD_SWAPQ(shdr.s_size) > 0) { p = calloc(MD_SWAPQ(shdr.s_size), sizeof(char)); if (!p) fatal("out of virtual memory"); if (fseek(fobj, MD_SWAPQ(shdr.s_scnptr), 0) == -1) fatal("could not read `.text' from executable", i); if (fread(p, MD_SWAPQ(shdr.s_size), 1, fobj) < 1) fatal("could not read text section from executable"); /* copy program section into simulator target memory */ mem_bcopy(mem_access, mem, Write, MD_SWAPQ(shdr.s_vaddr), p, MD_SWAPQ(shdr.s_size)); /* release the section buffer */ free(p); } else warn("section `%s' is empty...", shdr.s_name); break; case ECOFF_STYP_LITA: case ECOFF_STYP_LIT8: case ECOFF_STYP_LIT4: case ECOFF_STYP_XDATA: case ECOFF_STYP_PDATA: case ECOFF_STYP_RCONST: /* fall through */ case ECOFF_STYP_RDATA: /* The .rdata section is sometimes placed before the text * section instead of being contiguous with the .data section. */ #if 0 Rdata_start = MD_SWAPQ(shdr.s_vaddr); Rdata_size = MD_SWAPQ(shdr.s_size); Rdata_seek = MD_SWAPQ(shdr.s_scnptr); #endif /* fall through */ case ECOFF_STYP_DATA: #if 0 Data_seek = MD_SWAPQ(shdr.s_scnptr); #endif /* fall through */ case ECOFF_STYP_SDATA: #if 0 Sdata_seek = MD_SWAPQ(shdr.s_scnptr); #endif if (MD_SWAPQ(shdr.s_size) > 0) { p = calloc(MD_SWAPQ(shdr.s_size), sizeof(char)); if (!p) fatal("out of virtual memory"); if (fseek(fobj, MD_SWAPQ(shdr.s_scnptr), 0) == -1) fatal("could not read `.text' from executable", i); if (fread(p, MD_SWAPQ(shdr.s_size), 1, fobj) < 1) fatal("could not read text section from executable"); /* copy program section it into simulator target memory */ mem_bcopy(mem_access, mem, Write, MD_SWAPQ(shdr.s_vaddr), p, MD_SWAPQ(shdr.s_size)); /* release the section buffer */ free(p); } else warn("section `%s' is empty...", shdr.s_name); break; case ECOFF_STYP_BSS: case ECOFF_STYP_SBSS: /* no data to read... */ break; default: warn("section `%s' ignored...", shdr.s_name); } } /* done with the executable, close it */ if (fclose(fobj)) fatal("could not close executable `%s'", argv[0]); } #endif /* BFD_LOADER */ /* perform sanity checks on segment ranges */ if (!ld_text_base || !ld_text_size) fatal("executable is missing a `.text' section"); if (!ld_data_base || !ld_data_size) fatal("executable is missing a `.data' section"); if (!ld_prog_entry) fatal("program entry point not specified"); /* determine byte/words swapping required to execute on this host */ sim_swap_bytes = (endian_host_byte_order() != endian_target_byte_order()); if (sim_swap_bytes) { #if 0 /* FIXME: disabled until further notice... */ /* cross-endian is never reliable, why this is so is beyond the scope of this comment, e-mail me for details... */ fprintf(stderr, "sim: *WARNING*: swapping bytes to match host...\n"); fprintf(stderr, "sim: *WARNING*: swapping may break your program!\n"); /* #else */ fatal("binary endian does not match host endian"); #endif } sim_swap_words = (endian_host_word_order() != endian_target_word_order()); if (sim_swap_words) { #if 0 /* FIXME: disabled until further notice... */ /* cross-endian is never reliable, why this is so is beyond the scope of this comment, e-mail me for details... */ fprintf(stderr, "sim: *WARNING*: swapping words to match host...\n"); fprintf(stderr, "sim: *WARNING*: swapping may break your program!\n"); /* #else */ fatal("binary endian does not match host endian"); #endif } /* set up a local stack pointer, this is where the argv and envp data is written into program memory */ ld_stack_base = ld_text_base - (409600+4096); #if 0 sp = ROUND_DOWN(ld_stack_base - MD_MAX_ENVIRON, sizeof(MD_DOUBLE_TYPE)); #endif sp = ld_stack_base - MD_MAX_ENVIRON; ld_stack_size = ld_stack_base - sp; printf("Thread 0 stack size (4)%d\n", current->ld_stack_size); /* initial stack pointer value */ ld_environ_base = sp; /* write [argc] to stack */ temp = MD_SWAPQ(argc); mem_access(mem, Write, sp, &temp, sizeof(qword_t)); regs->regs_R[MD_REG_A0] = temp; sp += sizeof(qword_t); /* skip past argv array and NULL */ argv_addr = sp; regs->regs_R[MD_REG_A1] = argv_addr; sp = sp + (argc + 1) * sizeof(md_addr_t); /* save space for envp array and NULL */ envp_addr = sp; for (i=0; envp[i]; i++) sp += sizeof(md_addr_t); sp += sizeof(md_addr_t); /* fill in the argv pointer array and data */ for (i=0; i<argc; i++) { /* write the argv pointer array entry */ temp = MD_SWAPQ(sp); mem_access(mem, Write, argv_addr + i*sizeof(md_addr_t), &temp, sizeof(md_addr_t)); /* and the data */ mem_strcpy(mem_access, mem, Write, sp, argv[i]); sp += strlen(argv[i])+1; } /* terminate argv array with a NULL */ mem_access(mem, Write, argv_addr + i*sizeof(md_addr_t), &null_ptr, sizeof(md_addr_t)); /* write envp pointer array and data to stack */ for (i = 0; envp[i]; i++) { /* write the envp pointer array entry */ temp = MD_SWAPQ(sp); mem_access(mem, Write, envp_addr + i*sizeof(md_addr_t), &temp, sizeof(md_addr_t)); /* and the data */ mem_strcpy(mem_access, mem, Write, sp, envp[i]); sp += strlen(envp[i]) + 1; } /* terminate the envp array with a NULL */ mem_access(mem, Write, envp_addr + i*sizeof(md_addr_t), &null_ptr, sizeof(md_addr_t)); /* did we tromp off the stop of the stack? */ if (sp > ld_stack_base) { /* we did, indicate to the user that MD_MAX_ENVIRON must be increased, alternatively, you can use a smaller environment, or fewer command line arguments */ fatal("environment overflow, increase MD_MAX_ENVIRON in alpha.h"); } /* initialize the bottom of heap to top of data segment */ ld_brk_point = ROUND_UP(ld_data_base + ld_data_size, MD_PAGE_SIZE); /* set initial minimum stack pointer value to initial stack value */ ld_stack_min = regs->regs_R[MD_REG_SP]; regs->regs_R[MD_REG_SP] = ld_environ_base; regs->regs_PC = ld_prog_entry; printf("ld_text_base: 0x%08x ld_text_size: 0x%08x", ld_text_base, ld_text_size); printf("ld_data_base: 0x%08x ld_data_size: 0x%08x", ld_data_base, ld_data_size); printf("ld_stack_base: 0x%08x ld_stack_size: 0x%08x", ld_stack_base, ld_stack_size); printf("ld_prog_entry: 0x%08x", ld_prog_entry); debug("ld_text_base: 0x%08x ld_text_size: 0x%08x", ld_text_base, ld_text_size); debug("ld_data_base: 0x%08x ld_data_size: 0x%08x", ld_data_base, ld_data_size); debug("ld_stack_base: 0x%08x ld_stack_size: 0x%08x", ld_stack_base, ld_stack_size); debug("ld_prog_entry: 0x%08x", ld_prog_entry); }
/* load program text and initialized data into simulated virtual memory space and initialize program segment range variables */ void ld_load_prog(char *fname, /* program to load */ int argc, char **argv, /* simulated program cmd line args */ char **envp, /* simulated program environment */ struct regs_t *regs, /* registers to initialize for load */ struct mem_t *mem, /* memory space to load prog into */ int zero_bss_segs) /* zero uninit data segment? */ { int i; word_t temp; md_addr_t sp, data_break = 0, null_ptr = 0, argv_addr, envp_addr; FILE *fobj; struct elf_filehdr fhdr; struct elf_scnhdr shdr; byte_t *strtab, *buffer; if (eio_valid(fname)) { if (argc != 1) { fprintf(stderr, "error: EIO file has arguments\n"); exit(1); } fprintf(stderr, "sim: loading EIO file: %s\n", fname); sim_eio_fname = mystrdup(fname); /* open the EIO file stream */ sim_eio_fd = eio_open(fname); /* load initial state checkpoint */ if (eio_read_chkpt(regs, mem, sim_eio_fd) != -1) fatal("bad initial checkpoint in EIO file"); /* load checkpoint? */ if (sim_chkpt_fname != NULL) { counter_t restore_icnt; FILE *chkpt_fd; fprintf(stderr, "sim: loading checkpoint file: %s\n", sim_chkpt_fname); if (!eio_valid(sim_chkpt_fname)) fatal("file `%s' does not appear to be a checkpoint file", sim_chkpt_fname); /* open the checkpoint file */ chkpt_fd = eio_open(sim_chkpt_fname); /* load the state image */ restore_icnt = eio_read_chkpt(regs, mem, chkpt_fd); /* fast forward the baseline EIO trace to checkpoint location */ myfprintf(stderr, "sim: fast forwarding to instruction %n\n", restore_icnt); eio_fast_forward(sim_eio_fd, restore_icnt); } /* computed state... */ ld_environ_base = regs->regs_R[MD_REG_SP]; ld_prog_entry = regs->regs_PC; /* fini... */ return; } #ifdef MD_CROSS_ENDIAN else { warn("endian of `%s' does not match host", fname); warn("running with experimental cross-endian execution support"); warn("****************************************"); warn("**>> please check results carefully <<**"); warn("****************************************"); #if 0 fatal("SimpleScalar/ARM only supports binary execution on\n" " little-endian hosts, use EIO files on big-endian hosts"); #endif } #endif /* MD_CROSS_ENDIAN */ if (sim_chkpt_fname != NULL) fatal("checkpoints only supported while EIO tracing"); /* record profile file name */ ld_prog_fname = argv[0]; /* load the program into memory, try both endians */ #if defined(__CYGWIN32__) || defined(_MSC_VER) fobj = fopen(argv[0], "rb"); #else fobj = fopen(argv[0], "r"); #endif if (!fobj) fatal("cannot open executable `%s'", argv[0]); if (fread(&fhdr, sizeof(struct elf_filehdr), 1, fobj) < 1) fatal("cannot read header from executable `%s'", argv[0]); /* check if it is a valid ELF file */ if (!(fhdr.e_ident[EI_MAG0] == 0x7f && fhdr.e_ident[EI_MAG1] == 'E' && fhdr.e_ident[EI_MAG2] == 'L' && fhdr.e_ident[EI_MAG3] == 'F')) fatal("bad magic number in executable `%s' (not an executable)", argv[0]); /* check if the file is executable */ if (fhdr.e_type != ET_EXEC) fatal("object file `%s' is not executable", argv[0]); /* check if the file is for ARM architecture */ if (fhdr.e_machine != EM_ARM) fatal("executable file `%s' is not for the ARM architecture", argv[0]); ld_prog_entry = fhdr.e_entry; debug("number of sections in executable = %d\n", fhdr.e_shnum); debug("offset to section header table = %d", fhdr.e_shoff); /* seek to the beginning of the first section header, the file header comes first, followed by the optional header (this is the aouthdr), the size of the aouthdr is given in Fdhr.f_opthdr */ fseek(fobj, fhdr.e_shoff + (fhdr.e_shstrndx * fhdr.e_shentsize), SEEK_SET); if (fread(&shdr, sizeof(struct elf_scnhdr), 1, fobj) < 1) fatal("error reading string section header from `%s'", argv[0]); /* allocate space for string table */ strtab = (char *)calloc(shdr.sh_size, sizeof(char)); if (!strtab) fatal("out of virtual memory"); /* read the string table */ if (fseek(fobj, shdr.sh_offset, SEEK_SET) < 0) fatal("cannot seek to string table section"); if (fread(strtab, shdr.sh_size, 1, fobj) < 0) fatal("cannot read string table section"); debug("size of string table = %d", shdr.sh_size); debug("type of section = %d", shdr.sh_type); debug("offset of string table in file = %d", shdr.sh_offset); debug("processing %d sections in `%s'...", fhdr.e_shnum, argv[0]); /* loop through the section headers */ for (i=0; i < fhdr.e_shnum; i++) { buffer = NULL; if (fseek(fobj, fhdr.e_shoff + (i * fhdr.e_shentsize), SEEK_SET) < 0) fatal("could not reset location in executable"); if (fread(&shdr, sizeof(struct elf_scnhdr), 1, fobj) < 1) fatal("could not read section %d from executable", i); /* make sure the file is static */ if (shdr.sh_type == SHT_DYNAMIC || shdr.sh_type == SHT_DYNSYM) fatal("file is dynamically linked, compile with `-static'"); debug("processing section `%s'...", &strtab[shdr.sh_name]); debug(" section flags = 0x%08x", shdr.sh_flags); debug(" section type = %d", shdr.sh_type); debug(" section address = 0x%08x", shdr.sh_addr); debug(" section offset = %d", shdr.sh_offset); debug(" section size = %d", shdr.sh_size); debug(" section link = %d", shdr.sh_link); debug(" section extra info = %d", shdr.sh_info); debug(" section entry size = %d", shdr.sh_entsize); if (shdr.sh_addr != 0 && shdr.sh_size != 0 && (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS)) { /* if the ELF format designates an address for the section then load it into memory */ debug(" processing section `%s'...", &strtab[shdr.sh_name]); if ((shdr.sh_flags & SHF_ALLOC) != 0 && shdr.sh_type != SHT_NOBITS) { debug(" loading section `%s'...", &strtab[shdr.sh_name]); /* go to the offset in file where section is located */ if (fseek(fobj, shdr.sh_offset, SEEK_SET) < 0) fatal("cannot file pointer"); /* allocate memory for the section contents */ buffer = (char *)calloc(shdr.sh_size, sizeof(byte_t)); if (!buffer) fatal("out of virtual memory"); /* read section into buffer */ if (fread(buffer, shdr.sh_size, 1, fobj) < 1) fatal("could not read all the contents of section"); /* copy the section contents into simulator target memory */ mem_bcopy(mem_access, mem, Write, shdr.sh_addr, buffer, shdr.sh_size); } /* update program space limits */ if ((shdr.sh_flags & SHF_EXECINSTR) != 0) { debug("updating text size..."); if (shdr.sh_addr < ld_text_base) ld_text_base = shdr.sh_addr; if ((shdr.sh_addr + shdr.sh_size) > ld_text_bound) ld_text_bound = shdr.sh_addr + shdr.sh_size; } else { debug("updating data size..."); if (shdr.sh_addr < ld_data_base) ld_data_base = shdr.sh_addr; if ((shdr.sh_addr + shdr.sh_size) > ld_data_bound) ld_data_bound = shdr.sh_addr + shdr.sh_size; } ld_text_size = ld_text_bound - ld_text_base; ld_data_size = ld_data_bound - ld_data_base; /* release buffer storage */ if (buffer != NULL) free(buffer); } } /* release string table storage */ free(strtab); /* perform sanity checks on segment ranges */ if (!ld_text_base || !ld_text_size) fatal("executable is missing a `.text' section"); if (!ld_data_base || !ld_data_size) fatal("executable is missing a `.data' section"); if (!ld_prog_entry) fatal("program entry point not specified"); /* determine byte/words swapping required to execute on this host */ sim_swap_bytes = (endian_host_byte_order() != endian_target_byte_order()); if (sim_swap_bytes) { #if 0 /* FIXME: disabled until further notice... */ /* cross-endian is never reliable, why this is so is beyond the scope of this comment, e-mail me for details... */ fprintf(stderr, "sim: *WARNING*: swapping bytes to match host...\n"); fprintf(stderr, "sim: *WARNING*: swapping may break your program!\n"); /* #else */ fatal("binary endian does not match host endian"); #endif } sim_swap_words = (endian_host_word_order() != endian_target_word_order()); if (sim_swap_words) { #if 0 /* FIXME: disabled until further notice... */ /* cross-endian is never reliable, why this is so is beyond the scope of this comment, e-mail me for details... */ fprintf(stderr, "sim: *WARNING*: swapping words to match host...\n"); fprintf(stderr, "sim: *WARNING*: swapping may break your program!\n"); /* #else */ fatal("binary endian does not match host endian"); #endif } /* set up a local stack pointer, this is where the argv and envp data is written into program memory */ /* ld_stack_base = ld_text_base - (409600+4096); */ ld_stack_base = 0xc0000000; #if 0 sp = ROUND_DOWN(ld_stack_base - MD_MAX_ENVIRON, sizeof(MD_DOUBLE_TYPE)); #endif sp = ld_stack_base - MD_MAX_ENVIRON; ld_stack_size = ld_stack_base - sp; /* initial stack pointer value */ ld_environ_base = sp; /* write [argc] to stack */ temp = argc; mem_access(mem, Write, sp, &temp, sizeof(word_t)); regs->regs_R[MD_REG_R1] = temp; sp += sizeof(word_t); /* skip past argv array and NULL */ argv_addr = sp; regs->regs_R[MD_REG_R2] = argv_addr; sp = sp + (argc + 1) * sizeof(md_addr_t); /* save space for envp array and NULL */ envp_addr = sp; for (i=0; envp[i]; i++) sp += sizeof(md_addr_t); sp += sizeof(md_addr_t); /* fill in the argv pointer array and data */ for (i=0; i<argc; i++) { /* write the argv pointer array entry */ temp = sp; mem_access(mem, Write, argv_addr + i*sizeof(md_addr_t), &temp, sizeof(md_addr_t)); /* and the data */ mem_strcpy(mem_access, mem, Write, sp, argv[i]); sp += strlen(argv[i])+1; } /* terminate argv array with a NULL */ mem_access(mem, Write, argv_addr + i*sizeof(md_addr_t), &null_ptr, sizeof(md_addr_t)); /* write envp pointer array and data to stack */ for (i = 0; envp[i]; i++) { /* write the envp pointer array entry */ temp = sp; mem_access(mem, Write, envp_addr + i*sizeof(md_addr_t), &temp, sizeof(md_addr_t)); /* and the data */ mem_strcpy(mem_access, mem, Write, sp, envp[i]); sp += strlen(envp[i]) + 1; } /* terminate the envp array with a NULL */ mem_access(mem, Write, envp_addr + i*sizeof(md_addr_t), &null_ptr, sizeof(md_addr_t)); /* did we tromp off the stop of the stack? */ if (sp > ld_stack_base) { /* we did, indicate to the user that MD_MAX_ENVIRON must be increased, alternatively, you can use a smaller environment, or fewer command line arguments */ fatal("environment overflow, increase MD_MAX_ENVIRON in arm.h"); } /* initialize the bottom of heap to top of data segment */ ld_brk_point = ROUND_UP(ld_data_base + ld_data_size, MD_PAGE_SIZE); /* set initial minimum stack pointer value to initial stack value */ ld_stack_min = regs->regs_R[MD_REG_SP]; regs->regs_R[MD_REG_SP] = ld_environ_base; regs->regs_PC = ld_prog_entry; debug("ld_text_base: 0x%08x ld_text_size: 0x%08x", ld_text_base, ld_text_size); debug("ld_data_base: 0x%08x ld_data_size: 0x%08x", ld_data_base, ld_data_size); debug("ld_stack_base: 0x%08x ld_stack_size: 0x%08x", ld_stack_base, ld_stack_size); debug("ld_prog_entry: 0x%08x", ld_prog_entry); }
void sys_syscall(struct regs_t *regs, /* registers to access */ mem_access_fn mem_fn, /* generic memory accessor */ struct mem_t *mem, /* memory space to access */ md_inst_t inst, /* system call inst */ int traceable) /* traceable system call? */ { /* Figure out the system call number from the swi instruction Last 24 bits gives us this number */ word_t syscode = inst & 0x000fffff; /* first, check if an EIO trace is being consumed... */ /* Left from Alpha code should be the same in ARM though */ if (traceable && sim_eio_fd != NULL) { eio_read_trace(sim_eio_fd, sim_num_insn, regs, mem_fn, mem, inst); #if 0 /* kludge fix for sigreturn(), it modifies all registers */ if (syscode == ARM_SYS_sigreturn) { int i; struct osf_sigcontext sc; md_addr_t sc_addr = regs->regs_R[MD_REG_R0]; /* change the register name to r0 (first arg) */ mem_bcopy(mem_fn, mem, Read, sc_addr, &sc, sizeof(struct osf_sigcontext)); regs->regs_NPC = sc.sc_pc; for (i=0; i < 32; ++i) regs->regs_R[i] = sc.sc_regs[i]; for (i=0; i < 32; ++i) regs->regs_F.q[i] = sc.sc_fpregs[i]; regs->regs_C.fpcr = sc.sc_fpcr; } #endif /* fini... */ return; } /* no, OK execute the live system call... */ switch (syscode) { case SIMIPS_SYS_exit: /* exit jumps to the target set in main() */ longjmp(sim_exit_buf,/* exitcode + fudge */0); break; case SIMIPS_SYS_print: { md_addr_t _begin_addr; word_t _length; int * data = NULL; int i; _begin_addr = regs->regs_R[1]; _length = regs->regs_R[2]; data = (int *) calloc(_length, sizeof(int)); mem_bcopy(mem_fn, mem, Read, _begin_addr, (char *)data, (sizeof(int)*_length)); for(i=0;i<_length;i++ ) printf("%d\n", data[i]); } break; case SIMIPS_SYS_delim: { printf("----------------------\n"); break; } default: warn("invalid/unimplemented syscall %d, PC=0x%08p, winging it", (int)syscode, regs->regs_PC); } if (verbose) fprintf(stderr, "syscall(%d):\n",(int)syscode); }