static bool rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec_t* rec, void* data) { if (rec->type == rtems_rtl_unresolved_name) { rtems_rtl_unresolved_reloc_data_t* rd; rd = (rtems_rtl_unresolved_reloc_data_t*) data; ++rd->name; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: lookup: %d: %s\n", rd->name, rec->rec.name.name); rd->sym = rtems_rtl_symbol_global_find (rec->rec.name.name); if (rd->sym) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: found: %s\n", rec->rec.name.name); rd->name_rec = rec; rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd); rd->name_rec = NULL; rd->sym = NULL; } } return false; }
static bool rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec_t* rec, void* data) { if (rec->type == rtems_rtl_unresolved_reloc) { rtems_rtl_unresolved_reloc_data_t* rd; rd = (rtems_rtl_unresolved_reloc_data_t*) data; if (rec->rec.reloc.name == rd->name) { if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name); rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym); /* * Set the object pointer to NULL to indicate the record is not used * anymore. Update the reference count of the name. The sweep after * relocating will remove the reloc records with obj set to NULL and * names with a reference count of 0. */ rec->rec.reloc.obj = NULL; if (rd->name_rec && rd->name_rec->rec.name.refs) --rd->name_rec->rec.name.refs; } } return false; }
bool rtems_rtl_obj_add_section (rtems_rtl_obj_t* obj, int section, const char* name, size_t size, off_t offset, uint32_t alignment, int link, int info, uint32_t flags) { rtems_rtl_obj_sect_t* sect = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sizeof (rtems_rtl_obj_sect_t), true); if (!sect) { rtems_rtl_set_error (ENOMEM, "adding allocated section"); return false; } sect->section = section; sect->name = rtems_rtl_strdup (name); sect->size = size; sect->offset = offset; sect->alignment = alignment; sect->link = link; sect->info = info; sect->flags = flags; sect->base = NULL; rtems_chain_append (&obj->sections, §->node); if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION)) printf ("rtl: sect: %-2d: %s\n", section, name); return true; }
void rtems_rtl_alloc_indirect_new (rtems_rtl_alloc_tag_t tag, rtems_rtl_ptr_t* handle, size_t size) { rtems_rtl_data_t* rtl = rtems_rtl_lock (); if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) { if (!rtems_rtl_ptr_null (handle)) printf ("rtl: alloc: inew: %s handle=%p: not null\n", rtems_rtl_trace_tag_label (tag), handle); printf ("rtl: alloc: inew: %s handle=%p size=%zd\n", rtems_rtl_trace_tag_label (tag), handle, size); } if (rtl) { rtems_rtl_alloc_data_t* allocator = &rtl->allocator; handle->pointer = rtems_rtl_alloc_new (tag, size, false); if (!rtems_rtl_ptr_null (handle)) rtems_chain_append_unprotected (&allocator->indirects[tag], &handle->node); } rtems_rtl_unlock (); }
static size_t rtems_rtl_obj_sections_loader (uint32_t mask, rtems_rtl_obj_t* obj, int fd, uint8_t* base, rtems_rtl_obj_sect_handler_t handler, void* data) { rtems_chain_control* sections = &obj->sections; rtems_chain_node* node = rtems_chain_first (sections); size_t base_offset = 0; bool first = true; while (!rtems_chain_is_tail (sections, node)) { rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node; if ((sect->size != 0) && ((sect->flags & mask) != 0)) { if (!first) base_offset = rtems_rtl_sect_align (base_offset, sect->alignment); sect->base = base + base_offset; if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) printf ("rtl: loading: %s -> %8p (%zi)\n", sect->name, sect->base, sect->size); if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD) { if (!handler (obj, fd, sect, data)) { sect->base = 0; return false; } } else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO) { memset (base + base_offset, 0, sect->size); } else { sect->base = 0; rtems_rtl_set_error (errno, "section has no load op"); return false; } base_offset += sect->size; first = false; } node = rtems_chain_next (node); } return true; }
void rtems_rtl_unresolved_resolve (void) { rtems_rtl_unresolved_reloc_data_t rd; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: global resolve\n"); rd.name = 0; rd.name_rec = NULL; rd.sym = NULL; rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_iterator, &rd); rtems_rtl_unresolved_compact (); }
void rtems_rtl_alloc_del (rtems_rtl_alloc_tag_t tag, void* address) { rtems_rtl_data_t* rtl = rtems_rtl_lock (); if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) printf ("rtl: alloc: del: %s addr=%p\n", rtems_rtl_trace_tag_label (tag), address); if (rtl && address) rtl->allocator.allocator (false, tag, &address, 0); rtems_rtl_unlock (); }
void* rtems_rtl_alloc_new (rtems_rtl_alloc_tag_t tag, size_t size, bool zero) { rtems_rtl_data_t* rtl = rtems_rtl_lock (); void* address = NULL; if (rtl) rtl->allocator.allocator (true, tag, &address, size); rtems_rtl_unlock (); if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) printf ("rtl: alloc: new: %s addr=%p size=%zu\n", rtems_rtl_trace_tag_label (tag), address, size); if (zero) memset (address, 0, size); return address; }
void rtems_rtl_alloc_indirect_del (rtems_rtl_alloc_tag_t tag, rtems_rtl_ptr_t* handle) { rtems_rtl_data_t* rtl = rtems_rtl_lock (); if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR)) { if (rtems_rtl_ptr_null (handle)) printf ("rtl: alloc: idel: %s handle=%p: is null\n", rtems_rtl_trace_tag_label (tag), handle); printf ("rtl: alloc: idel: %s handle=%p\n", rtems_rtl_trace_tag_label (tag), handle); } if (rtl && !rtems_rtl_ptr_null (handle)) { rtems_chain_extract_unprotected (&handle->node); rtems_rtl_alloc_del (tag, &handle->pointer); } }
/* * 1. _gp_disp symbol are not considered in this file. * 2. There is a local/external column; * local corresponds to (STB_LOCAL & STT_SECTION) and * all others are external. Because if the type of a * symbol is STT_SECTION, it must be STB_LOCAL. Thus * just consider symtype here. */ bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr *where; Elf_Word tmp; Elf_Word addend = (Elf_Word)0; Elf_Word local = 0; uint32_t t; static Elf_Addr *where_hi16; static Elf_Addr ahl; where = (Elf_Addr *)(sect->base + rel->r_offset); addend = *where; if (syminfo == STT_SECTION) local = 1; switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; case R_TYPE(16): tmp = addend & 0xffff; if ((tmp & 0x8000) == 0x8000) tmp |= 0xffff0000; /* Sign extend */ tmp = symvalue + (int)tmp; if ((tmp & 0xffff0000) != 0) { printf("R_MIPS_16 Overflow\n"); return false; } *where = (tmp & 0xffff) | (*where & 0xffff0000); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_16 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(32): tmp = symvalue + addend; if (addend != tmp) *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: R_MIPS_32 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(26): addend &= 0x03ffffff; addend <<= 2; if (local == 1) { /* STB_LOCAL and STT_SECTION */ tmp = symvalue + (((Elf_Addr)where & 0xf0000000) | addend); tmp >>= 2; } else { /* external */
bool rtems_rtl_unresolved_add (rtems_rtl_obj_t* obj, const uint16_t flags, const char* name, const uint16_t sect, const rtems_rtl_word_t* rel) { rtems_rtl_unresolved_t* unresolved; rtems_chain_node* node; rtems_rtl_unresolv_block_t* block; rtems_rtl_unresolv_rec_t* rec; int name_index; size_t name_recs; if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED)) printf ("rtl: unresolv: add: %s(s:%d) -> %s\n", rtems_rtl_obj_oname (obj), sect, name); unresolved = rtems_rtl_unresolved (); if (!unresolved) return false; /* * Find the first block with a spare record. */ node = rtems_chain_first (&unresolved->blocks); block = NULL; while (!rtems_chain_is_tail (&unresolved->blocks, node)) { block = (rtems_rtl_unresolv_block_t*) node; if (block->recs < unresolved->block_recs) break; block = NULL; node = rtems_chain_next (node); } /* * No blocks with any spare records, allocate a new block. */ if (!block) { block = rtems_rtl_unresolved_block_alloc (unresolved); if (!block) return false; } name_index = rtems_rtl_unresolved_find_name (unresolved, name, true); name_recs = rtems_rtl_unresolved_name_recs (name); /* * An index less than 0 means the name is present and "0 - index" is the next * index to use. */ if (name_index < 0) { rtems_rtl_unresolv_block_t* name_block = block; /* * Is there enough room to fit the name ? It not add a new block. */ if (name_recs > (unresolved->block_recs - block->recs)) { name_block = rtems_rtl_unresolved_block_alloc (unresolved); if (!name_block) return false; } rec = rtems_rtl_unresolved_rec_first_free (name_block); rec->type = rtems_rtl_unresolved_name; rec->rec.name.refs = 1; rec->rec.name.length = strlen (name) + 1; memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1); block->recs += name_recs; name_index = 0 - name_index; /* * If the name block is the reloc block and it is full allocate a new * block for the relocation record. */ if ((block == name_block) && (block->recs >= unresolved->block_recs)) { block = rtems_rtl_unresolved_block_alloc (unresolved); if (!block) return false; } } rec = rtems_rtl_unresolved_rec_first_free (block); rec->type = rtems_rtl_unresolved_reloc; rec->rec.reloc.obj = obj; rec->rec.reloc.flags = flags; rec->rec.reloc.name = name_index; rec->rec.reloc.sect = sect; rec->rec.reloc.rel[0] = rel[0]; rec->rec.reloc.rel[1] = rel[1]; rec->rec.reloc.rel[2] = rel[2]; ++block->recs; return true; }
bool rtems_rtl_elf_relocate_rela (const rtems_rtl_obj_t* obj, const Elf_Rela* rela, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr* where; Elf_Word tmp; uint32_t mask = 0; uint32_t bits = 0; where = (Elf_Addr *)(sect->base + rela->r_offset); switch (ELF_R_TYPE(rela->r_info)) { case R_TYPE(NONE): break; case R_TYPE(32): /* * value:1; Field: word32; Expression: S + A */ *where = symvalue + rela->r_addend; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: ADDR32 %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(14): /* * value:7; Field: low14*; Expression: (S + A) >> 2 */ case R_TYPE(24): /* * value:2; Field: low24*; Expression: (S + A) >> 2 */ if (ELF_R_TYPE(rela->r_info) == R_TYPE(14)) { bits = 14; mask = 0xfffc; } else { bits = 24; mask = 0x3fffffc; } tmp = (symvalue + rela->r_addend) >> 2; if (tmp > ((1<<bits) - 1 )) { printf("Overflow ADDR14/ADDR24\n"); return false; } tmp = *where; tmp &= ~mask; tmp |= (symvalue + rela->r_addend) & mask; *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_HA): /* * value:6; Field:half16; Expression: #ha(S+A) */ tmp = symvalue + rela->r_addend; *(uint16_t *)where = (((tmp >> 16) + ((tmp & 0x8000) ? 1: 0)) & 0xffff); if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_HA %p @ %p in %s\n", (void *)*(where), where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_HI): /* * value:5; Field:half16; Expression: #hi(S+A) */ *(uint16_t *)where = ((symvalue + rela->r_addend) >> 16) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_HI %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(16_LO): /* * value:4; Field:half16; Expression: #lo(S+A) */ *(uint16_t *)where = (symvalue + (rela->r_addend)) & 0xffff; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: 16_LO %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(REL14): /* * value:11; Field:low14*; Expression:(S+A-P)>>2 */ case R_TYPE(REL24): /* * value:10; Field:low24*; Expression:(S+A-P)>>2 */ if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL24)) { mask = 0x3fffffc; bits = 24; } else if (ELF_R_TYPE(rela->r_info) == R_TYPE(REL14)) { mask = 0xfffc; bits = 14; } tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2; if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) || ((Elf_Sword)tmp < -(1<<(bits-1)))) { printf("Overflow REL14/REL24\n"); return false; } tmp = *where; tmp &= ~mask; tmp |= (symvalue + rela->r_addend - (Elf_Addr)where) & mask; *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: REL24/REL14 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(REL32): /* * value:26; Field:word32*; Expression:S+A-P */ *where = symvalue + rela->r_addend - (Elf_Addr)where; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: REL32 %p @ %p in %s\n", (void *)*where, where, rtems_rtl_obj_oname (obj)); break; default: printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " "contents = %p\n", ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info), (void *)rela->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %ld " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); return false; } return true; }
bool rtems_rtl_symbol_global_add (rtems_rtl_obj_t* obj, const unsigned char* esyms, unsigned int size) { rtems_rtl_symbols_t* symbols; rtems_rtl_obj_sym_t* sym; size_t count; size_t s; uint32_t marker; count = 0; s = 0; while ((s < size) && (esyms[s] != 0)) { int l = strlen ((char*) &esyms[s]); if ((esyms[s + l] != '\0') || ((s + l) > size)) { rtems_rtl_set_error (EINVAL, "invalid exported symbol table"); return false; } ++count; s += l + sizeof (unsigned long) + 1; } /* * Check this is the correct end of the table. */ marker = esyms[s + 1]; marker <<= 8; marker |= esyms[s + 2]; marker <<= 8; marker |= esyms[s + 3]; marker <<= 8; marker |= esyms[s + 4]; if (marker != 0xdeadbeefUL) { rtems_rtl_set_error (ENOMEM, "invalid export symbol table"); return false; } if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) printf ("rtl: global symbol add: %zi\n", count); obj->global_size = count * sizeof (rtems_rtl_obj_sym_t); obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, obj->global_size, true); if (!obj->global_table) { obj->global_size = 0; rtems_rtl_set_error (ENOMEM, "no memory for global symbols"); return false; } symbols = rtems_rtl_global_symbols (); s = 0; sym = obj->global_table; while ((s < size) && (esyms[s] != 0)) { /* * Copy the void* using a union and memcpy to avoid any strict aliasing or * alignment issues. The variable length of the label and the packed nature * of the table means casting is not suitable. */ union { uint8_t data[sizeof (void*)]; void* value; } copy_voidp; int b; sym->name = (const char*) &esyms[s]; s += strlen (sym->name) + 1; for (b = 0; b < sizeof (void*); ++b, ++s) copy_voidp.data[b] = esyms[s]; sym->value = copy_voidp.value; if (rtems_rtl_trace (RTEMS_RTL_TRACE_GLOBAL_SYM)) printf ("rtl: esyms: %s -> %8p\n", sym->name, sym->value); if (rtems_rtl_symbol_global_find (sym->name) == NULL) rtems_rtl_symbol_global_insert (symbols, sym); ++sym; } obj->global_syms = count; return true; }
bool rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj, const Elf_Rel* rel, const rtems_rtl_obj_sect_t* sect, const char* symname, const Elf_Byte syminfo, const Elf_Word symvalue) { Elf_Addr target = 0; Elf_Addr* where; Elf_Addr tmp; where = (Elf_Addr *)(sect->base + rel->r_offset); switch (ELF_R_TYPE(rel->r_info)) { case R_TYPE(NONE): break; case R_TYPE(PC32): target = (Elf_Addr) symvalue; *where += target - (Elf_Addr)where; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc PC32 in %s --> %p (%p @ %p) in %s\n", sect->name, (void*) symvalue, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(GOT32): case R_TYPE(32): case R_TYPE(GLOB_DAT): target = (Elf_Addr) symvalue; tmp = target + *where; if (*where != tmp) *where = tmp; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc 32/GLOB_DAT in %s --> %p @ %p in %s\n", sect->name, (void *)*where, where, rtems_rtl_obj_oname (obj)); break; case R_TYPE(RELATIVE): *where += (Elf_Addr)sect->base; if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) printf ("rtl: reloc RELATIVE in %s --> %p @ %p\n", rtems_rtl_obj_oname (obj), (void *)*where, where); break; case R_TYPE(COPY): printf ("rtl: reloc COPY (please report)\n"); break; default: printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " "contents = %p\n", ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, "%s: Unsupported relocation type %ld " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return false; } return true; }
bool rtems_rtl_obj_load_sections (rtems_rtl_obj_t* obj, int fd, rtems_rtl_obj_sect_handler_t handler, void* data) { size_t text_size; size_t const_size; size_t data_size; size_t bss_size; text_size = rtems_rtl_obj_text_size (obj) + rtems_rtl_obj_const_alignment (obj); const_size = rtems_rtl_obj_const_size (obj) + rtems_rtl_obj_data_alignment (obj); data_size = rtems_rtl_obj_data_size (obj) + rtems_rtl_obj_bss_alignment (obj); bss_size = rtems_rtl_obj_bss_size (obj); /* * Let the allocator manage the actual allocation. The user can use the * standard heap or provide a specific allocator with memory protection. */ if (!rtems_rtl_alloc_module_new (&obj->text_base, text_size, &obj->const_base, const_size, &obj->data_base, data_size, &obj->bss_base, bss_size)) { obj->exec_size = 0; rtems_rtl_set_error (ENOMEM, "no memory to load obj"); return false; } obj->exec_size = text_size + const_size + data_size + bss_size; if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT)) { printf ("rtl: load sect: text - b:%p s:%zi a:%" PRIu32 "\n", obj->text_base, text_size, rtems_rtl_obj_text_alignment (obj)); printf ("rtl: load sect: const - b:%p s:%zi a:%" PRIu32 "\n", obj->const_base, const_size, rtems_rtl_obj_const_alignment (obj)); printf ("rtl: load sect: data - b:%p s:%zi a:%" PRIu32 "\n", obj->data_base, data_size, rtems_rtl_obj_data_alignment (obj)); printf ("rtl: load sect: bss - b:%p s:%zi a:%" PRIu32 "\n", obj->bss_base, bss_size, rtems_rtl_obj_bss_alignment (obj)); } /* * Load all text then data then bss sections in seperate operations so each * type of section is grouped together. */ if (!rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_TEXT, obj, fd, obj->text_base, handler, data) || !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_CONST, obj, fd, obj->const_base, handler, data) || !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_DATA, obj, fd, obj->data_base, handler, data) || !rtems_rtl_obj_sections_loader (RTEMS_RTL_OBJ_SECT_BSS, obj, fd, obj->bss_base, handler, data)) { rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->data_base, &obj->bss_base); obj->exec_size = 0; return false; } return true; }
bool rtems_rtl_find_file (const char* name, const char* paths, const char** file_name, size_t* size) { struct stat sb; *file_name = NULL; *size = 0; if (rtems_filesystem_is_delimiter (name[0]) || (name[0] == '.')) { if (stat (name, &sb) == 0) *file_name = rtems_rtl_strdup (name); } else if (paths) { const char* start; const char* end; int len; char* fname; start = paths; end = start + strlen (paths); len = strlen (name); while (!*file_name && (start != end)) { const char* delimiter = strchr (start, ':'); if (delimiter == NULL) delimiter = end; /* * Allocate the path fragment, separator, name, terminating nul. Form the * path then see if the stat call works. */ fname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, (delimiter - start) + 1 + len + 1, true); if (!fname) { rtems_rtl_set_error (ENOMEM, "no memory searching for file"); return false; } memcpy (fname, start, delimiter - start); fname[delimiter - start] = '/'; memcpy (fname + (delimiter - start) + 1, name, len); if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD)) printf ("rtl: find-file: path: %s\n", fname); if (stat (fname, &sb) < 0) rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, fname); else *file_name = fname; start = delimiter; if (start != end) ++start; } } if (!*file_name) return false; *size = sb.st_size; return true; }