static void read_section(struct GlobalVars *gv,struct ObjectUnit *u, uint32_t index,struct vobj_symbol *vsyms,int nsyms) { struct Section *s; lword dsize,fsize; int nrelocs; uint8_t type = ST_DATA; uint8_t prot = SP_READ; uint8_t flags = 0; uint8_t align,*data; char *attr; char *name = p; struct Reloc *last_reloc; int last_sym = -1; lword last_offs; uint16_t last_bpos = INVALID; skip_string(); /* section name */ for (attr=p; *attr; attr++) { switch (tolower((unsigned char)*attr)) { case 'w': prot |= SP_WRITE; break; case 'x': prot |= SP_EXEC; break; case 'c': type = ST_CODE; break; case 'd': type = ST_DATA; break; case 'u': type = ST_UDATA; flags |= SF_UNINITIALIZED; break; case 'a': flags |= SF_ALLOC; } } skip_string(); read_number(); /* ignore flags */ align = (uint8_t)lshiftcnt(read_number()); dsize = read_number(); /* total size of section */ nrelocs = (int)read_number(); /* number of relocation entries */ fsize = read_number(); /* size in file, without 0-bytes */ if (type == ST_UDATA) { data = NULL; } else if (dsize > fsize) { /* recreate 0-bytes at end of section */ data = alloczero((size_t)dsize); memcpy(data,p,(size_t)fsize); } else data = p; /* create and add section */ p += fsize; s = add_section(u,name,data,(unsigned long)dsize,type,flags,prot,align,0); s->id = index; /* create relocations and unkown symbol references for this section */ for (last_reloc=NULL,last_offs=-1; nrelocs>0; nrelocs--) { struct Reloc *r; char *xrefname = NULL; lword offs,mask,addend; uint16_t bpos,bsiz; uint8_t flags; int sym_idx; /* read one relocation entry */ type = (uint8_t)read_number(); offs = read_number(); bpos = (uint16_t)read_number(); bsiz = (uint16_t)read_number(); mask = read_number(); addend = read_number(); sym_idx = (int)read_number() - 1; /* symbol index */ flags = 0; if (type>R_NONE && type<=LAST_STANDARD_RELOC && offs>=0 && bsiz<=(sizeof(lword)<<3) && sym_idx>=0 && sym_idx<nsyms) { if (vsyms[sym_idx].type == LABSYM) { xrefname = NULL; index = vsyms[sym_idx].sec; } else if (vsyms[sym_idx].type == IMPORT) { xrefname = vsyms[sym_idx].name; if (vsyms[sym_idx].flags & WEAK) flags |= RELF_WEAK; /* undefined weak symbol */ index = 0; } else { /* VOBJ relocation not supported */ error(115,getobjname(u),fff[u->lnkfile->format]->tname, (int)type,(lword)offs,(int)bpos,(int)bsiz,(lword)mask, vsyms[sym_idx].name,(int)vsyms[sym_idx].type); } if (sym_idx==last_sym && offs==last_offs && bpos==last_bpos && last_reloc!=NULL) { r = last_reloc; } else { r = newreloc(gv,s,xrefname,NULL,index,(unsigned long)offs,type,addend); r->flags |= flags; last_reloc = r; last_offs = offs; last_bpos = bpos; last_sym = sym_idx; } addreloc(s,r,bpos,bsiz,mask); /* make sure that section reflects the addend for other formats */ writesection(gv,data+(uint32_t)offs,r,addend); } else if (type != R_NONE) { /* VOBJ relocation not supported */ error(115,getobjname(u),fff[u->lnkfile->format]->tname, (int)type,(lword)offs,(int)bpos,(int)bsiz,(lword)mask, (sym_idx>=0&&sym_idx<nsyms) ? vsyms[sym_idx].name : "?", (sym_idx>=0&&sym_idx<nsyms) ? (int)vsyms[sym_idx].type : 0); } } }
/** ini_puts() * \param Section the name of the section to write the string in * \param Key the name of the entry to write, or NULL to erase all keys in the section * \param Value a pointer to the buffer the string, or NULL to erase the key * \param Filename the name and full path of the .ini file to write to * * \return 1 if successful, otherwise 0 */ int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename) { INI_FILETYPE rfp; INI_FILETYPE wfp; TCHAR *sp, *ep; TCHAR LocalBuffer[INI_BUFFERSIZE]; int len, match, count; assert(Filename!=NULL); if (!ini_openread(Filename, &rfp)) { /* If the .ini file doesn't exist, make a new file */ if (Key!=NULL && Value!=NULL) { if (!ini_openwrite(Filename, &wfp)) return 0; writesection(LocalBuffer, Section, &wfp); writekey(LocalBuffer, Key, Value, &wfp); ini_close(&wfp); } /* if */ return 1; } /* if */ /* If parameters Key and Value are valid (so this is not an "erase" request) * and the setting already exists and it already has the correct value, do * nothing. This early bail-out avoids rewriting the INI file for no reason. */ if (Key!=NULL && Value!=NULL) { match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer)); if (match && _tcscmp(LocalBuffer,Value)==0) { ini_close(&rfp); return 1; } /* if */ /* key not found, or different value -> proceed (but rewind the input file first) */ ini_rewind(&rfp); } /* if */ /* Get a temporary file name to copy to. Use the existing name, but with * the last character set to a '~'. */ ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); if (!ini_openwrite(LocalBuffer, &wfp)) { ini_close(&rfp); return 0; } /* if */ /* Move through the file one line at a time until a section is * matched or until EOF. Copy to temp file as it is read. */ count = 0; len = (Section != NULL) ? _tcslen(Section) : 0; if (len > 0) { do { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { /* Failed to find section, so add one to the end */ if (Key!=NULL && Value!=NULL) { ini_write(INI_LINETERM, &wfp); /* force a new line (there may not have been one) behind the last line of the INI file */ writesection(LocalBuffer, Section, &wfp); writekey(LocalBuffer, Key, Value, &wfp); } /* if */ /* Clean up and rename */ ini_close(&rfp); ini_close(&wfp); ini_remove(Filename); ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); ini_rename(LocalBuffer, Filename); return 1; } /* if */ /* Copy the line from source to dest, but not if this is the section that * we are looking for and this section must be removed */ sp = skipleading(LocalBuffer); ep = _tcschr(sp, ']'); match = (*sp == '[' && ep != NULL && (int)(ep-sp-1) == len && _tcsnicmp(sp + 1,Section,len) == 0); if (!match || Key!=NULL) { /* Remove blank lines, but insert a blank line (possibly one that was * removed on the previous iteration) before a new section. This creates * "neat" INI files. */ if (_tcslen(sp) > 0) { if (*sp == '[' && count > 0) ini_write(INI_LINETERM, &wfp); ini_write(sp, &wfp); count++; } /* if */ } /* if */ } while (!match); } /* if */ /* Now that the section has been found, find the entry. Stop searching * upon leaving the section's area. Copy the file as it is read * and create an entry if one is not found. */ len = (Key!=NULL) ? _tcslen(Key) : 0; for( ;; ) { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { /* EOF without an entry so make one */ if (Key!=NULL && Value!=NULL) { ini_write(INI_LINETERM, &wfp); /* force a new line (there may not have been one) behind the last line of the INI file */ writekey(LocalBuffer, Key, Value, &wfp); } /* if */ /* Clean up and rename */ ini_close(&rfp); ini_close(&wfp); ini_remove(Filename); ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); ini_rename(LocalBuffer, Filename); return 1; } /* if */ sp = skipleading(LocalBuffer); ep = _tcschr(sp, '='); /* Parse out the equal sign */ if (ep == NULL) ep = _tcschr(sp, ':'); match = (ep != NULL && (int)(ep-sp) == len && _tcsnicmp(sp,Key,len) == 0); if ((Key!=NULL && match) || *sp == '[') break; /* found the key, or found a new section */ /* in the section that we re-write, do not copy empty lines */ if (Key!=NULL && _tcslen(sp) > 0) ini_write(sp, &wfp); } /* for */ if (*sp == '[') { /* found start of new section, the key was not in the specified * section, so we add it just before the new section */ if (Key!=NULL && Value!=NULL) { /* We cannot use "writekey()" here, because we need to preserve the * contents of LocalBuffer. */ ini_write(Key, &wfp); ini_write("=", &wfp); ini_write(Value, &wfp); ini_write(INI_LINETERM INI_LINETERM, &wfp); /* put a blank line between the current and the next section */ } /* if */ /* write the new section header that we read previously */ ini_write(sp, &wfp); } else { /* We found the key; ignore the line just read (with the key and * the current value) and write the key with the new value. */ if (Key!=NULL && Value!=NULL) writekey(LocalBuffer, Key, Value, &wfp); } /* if */ /* Copy the rest of the INI file (removing empty lines, except before a section) */ while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { sp = skipleading(LocalBuffer); if (_tcslen(sp) > 0) { if (*sp == '[') ini_write(INI_LINETERM, &wfp); ini_write(sp, &wfp); } /* if */ } /* while */ /* Clean up and rename */ ini_close(&rfp); ini_close(&wfp); ini_remove(Filename); ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); ini_rename(LocalBuffer, Filename); return 1; }
/** ini_puts() * \param Section the name of the section to write the string in * \param Key the name of the entry to write, or NULL to erase all keys in the section * \param Value a pointer to the buffer the string, or NULL to erase the key * \param Filename the name and full path of the .ini file to write to * * \return 1 if successful, otherwise 0 */ int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename) { INI_FILETYPE rfp; INI_FILETYPE wfp; INI_FILEPOS mark; TCHAR *sp, *ep; TCHAR LocalBuffer[INI_BUFFERSIZE]; int len, match, flag, cachelen; assert(Filename != NULL); if (!ini_openread(Filename, &rfp)) { /* If the .ini file doesn't exist, make a new file */ if (Key != NULL && Value != NULL) { if (!ini_openwrite(Filename, &wfp)) return 0; writesection(LocalBuffer, Section, &wfp); writekey(LocalBuffer, Key, Value, &wfp); (void)ini_close(&wfp); } /* if */ return 1; } /* if */ /* If parameters Key and Value are valid (so this is not an "erase" request) * and the setting already exists and it already has the correct value, do * nothing. This early bail-out avoids rewriting the INI file for no reason. */ if (Key != NULL && Value != NULL) { (void)ini_tell(&rfp, &mark); match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer)); if (match && _tcscmp(LocalBuffer,Value) == 0) { (void)ini_close(&rfp); return 1; } /* if */ /* key not found, or different value -> proceed (but rewind the input file first) */ (void)ini_seek(&rfp, &mark); } /* if */ /* Get a temporary file name to copy to. Use the existing name, but with * the last character set to a '~'. */ ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE); if (!ini_openwrite(LocalBuffer, &wfp)) { (void)ini_close(&rfp); return 0; } /* if */ (void)ini_tell(&rfp, &mark); cachelen = 0; /* Move through the file one line at a time until a section is * matched or until EOF. Copy to temp file as it is read. */ len = (Section != NULL) ? _tcslen(Section) : 0; if (len > 0) { do { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { /* Failed to find section, so add one to the end */ flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); if (Key!=NULL && Value!=NULL) { if (!flag) (void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */ writesection(LocalBuffer, Section, &wfp); writekey(LocalBuffer, Key, Value, &wfp); } /* if */ return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ } /* if */ /* Copy the line from source to dest, but not if this is the section that * we are looking for and this section must be removed */ sp = skipleading(LocalBuffer); ep = _tcschr(sp, ']'); match = (*sp == '[' && ep != NULL && (int)(ep-sp-1) == len && _tcsnicmp(sp + 1,Section,len) == 0); if (!match || Key != NULL) { if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } /* if */ } /* if */ } while (!match); } /* if */ cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); /* when deleting a section, the section head that was just found has not been * copied to the output file, but because this line was not "accumulated" in * the cache, the position in the input file was reset to the point just * before the section; this must now be skipped (again) */ if (Key == NULL) { (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); (void)ini_tell(&rfp, &mark); } /* if */ /* Now that the section has been found, find the entry. Stop searching * upon leaving the section's area. Copy the file as it is read * and create an entry if one is not found. */ len = (Key!=NULL) ? _tcslen(Key) : 0; for( ;; ) { if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { /* EOF without an entry so make one */ flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); if (Key!=NULL && Value!=NULL) { if (!flag) (void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */ writekey(LocalBuffer, Key, Value, &wfp); } /* if */ return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ } /* if */ sp = skipleading(LocalBuffer); ep = _tcschr(sp, '='); /* Parse out the equal sign */ if (ep == NULL) ep = _tcschr(sp, ':'); match = (ep != NULL && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0); if ((Key != NULL && match) || *sp == '[') break; /* found the key, or found a new section */ /* copy other keys in the section */ if (Key == NULL) { (void)ini_tell(&rfp, &mark); /* we are deleting the entire section, so update the read position */ } else { if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } /* if */ } /* if */ } /* for */ /* the key was found, or we just dropped on the next section (meaning that it * wasn't found); in both cases we need to write the key, but in the latter * case, we also need to write the line starting the new section after writing * the key */ flag = (*sp == '['); cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); if (Key != NULL && Value != NULL) writekey(LocalBuffer, Key, Value, &wfp); /* cache_flush() reset the "read pointer" to the start of the line with the * previous key or the new section; read it again (because writekey() destroyed * the buffer) */ (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); if (flag) { /* the new section heading needs to be copied to the output file */ cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } else { /* forget the old key line */ (void)ini_tell(&rfp, &mark); } /* if */ /* Copy the rest of the INI file */ while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) { if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) { cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); (void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp); cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE); } /* if */ } /* while */ cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark); return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */ }
static void rawseg_writeexec(struct GlobalVars *gv,FILE *f) /* creates a new file for each segment, writes file name, start address */ /* and length into the output file */ { const char *fn = "rawseg_writeexec(): "; bool firstsec; unsigned long addr; FILE *segf; struct Phdr *p; struct LinkedSection *ls,*prevls; struct SegReloc *srlist; char buf[256]; for (p=gv->phdrlist; p; p=p->next) { if (p->type==PT_LOAD && (p->flags&PHDR_USED) && p->start!=ADDR_NONE && p->start_vma!=ADDR_NONE) { firstsec = TRUE; srlist = NULL; snprintf(buf,256,"%s.%s",gv->dest_name,p->name); segf = fopen(buf,"wb"); if (segf == NULL) { error(29,buf); /* cannot create file */ continue; } /* write file name, start address and length of segment to output */ fprintf(f,"\"%s\" 0x%llx 0x%llx\n",buf,p->start,p->mem_end-p->start); /* write segment's sections */ for (ls=(struct LinkedSection *)gv->lnksec.first; ls->n.next!=NULL; ls=(struct LinkedSection *)ls->n.next) { if (ls->copybase>=(unsigned long)p->start && (ls->copybase+ls->size)<=(unsigned long)p->mem_end && (ls->flags & SF_ALLOC)) { if (gv->keep_relocs) { /* remember relocations, adjusted from section to segment base */ struct Reloc *r; struct RelocInsert *ri; struct LinkedSection *relsec; struct Phdr *relph; for (r=(struct Reloc *)ls->relocs.first; r->n.next!=NULL; r=(struct Reloc *)r->n.next) { if (ri = r->insert) { if (r->rtype!=R_ABS || ri->bpos!=0 || ri->bsiz!=32) { /* only absolute 32-bit relocs are supported */ error(32,fff_rawseg.tname,reloc_name[r->rtype], (int)ri->bpos,(int)ri->bsiz,ri->mask, ls->name,r->offset); continue; } } else continue; if (r->relocsect.lnk == NULL) { if (r->flags & RELF_DYNLINK) continue; /* NULL, because it was resolved by a sh.obj. */ else ierror("%sReloc type %d (%s) at %s+0x%lx " "(addend 0x%llx) is missing a relocsect.lnk", fn,(int)r->rtype,reloc_name[r->rtype],ls->name, r->offset,r->addend); } relsec = r->relocsect.lnk; /* find out to which segment relsec belongs */ for (relph=gv->phdrlist; relph; relph=relph->next) { if (relph->type==PT_LOAD && (relph->flags&PHDR_USED) && relph->start!=ADDR_NONE && relph->start_vma!=ADDR_NONE) { if (relsec->copybase>=(unsigned long)relph->start && (relsec->copybase+relsec->size)<= (unsigned long)relph->mem_end && (relsec->flags & SF_ALLOC)) break; } } /* use segment's base address for relocation instead */ if (relph) { lword segoffs,a,v; struct SegReloc *newsr,*srp; segoffs = (lword)relsec->copybase - relph->start; v = writesection(gv,ls->data+r->offset,r,r->addend+segoffs); if (v != 0) { /* Calculated value doesn't fit into relocation type x ... */ if (ri = r->insert) error(35,gv->dest_name,ls->name,r->offset,v, reloc_name[r->rtype],(int)ri->bpos, (int)ri->bsiz,ri->mask); else ierror("%sReloc (%s+%lx), type=%s, without RelocInsert", fn,ls->name,r->offset,reloc_name[r->rtype]); } /* remember relocation offset and segment for later */ newsr = alloc(sizeof(struct SegReloc)); newsr->next = NULL; newsr->seg = relph; newsr->offset = (ls->copybase - (unsigned long)p->start) + r->offset; if (srp = srlist) { while (srp->next) srp = srp->next; srp->next = newsr; } else srlist = newsr; } else ierror("%sNo segment for reloc offset section '%s'", fn,relsec->name); } } else calc_relocs(gv,ls); if (!firstsec) { /* write an alignment gap, when needed */ if (ls->copybase > addr) fwritegap(segf,ls->copybase-addr); else if (ls->copybase < addr) error(98,fff[gv->dest_format]->tname,ls->name,prevls->name); } else firstsec = FALSE; fwritex(segf,ls->data,ls->size); addr = ls->copybase + ls->size; prevls = ls; } } fclose(segf); if (srlist) { /* write relocation files for this segment */ struct Phdr *relph; struct SegReloc *sr; uint32_t rcnt; FILE *rf; for (relph=gv->phdrlist; relph; relph=relph->next) { for (sr=srlist,rf=NULL,rcnt=0; sr; sr=sr->next) { if (sr->seg == relph) { if (!rf) { snprintf(buf,256,"%s.%s.rel%s", gv->dest_name,p->name,relph->name); rf = fopen(buf,"wb"); if (rf == NULL) { error(29,buf); /* cannot create file */ continue; } fwritegap(rf,4); /* number of relocs will be stored here */ } if (gv->endianess == _BIG_ENDIAN_) fwrite32be(rf,sr->offset); else fwrite32le(rf,sr->offset); rcnt++; } } if (rf) { /* write number of relocs into the first word */ fseek(rf,0,SEEK_SET); if (gv->endianess == _BIG_ENDIAN_) fwrite32be(rf,rcnt); else fwrite32le(rf,rcnt); fclose(rf); } } } } } }