elf_object.cc revision 5152
112SN/A/* 21762SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 312SN/A * All rights reserved. 412SN/A * 512SN/A * Redistribution and use in source and binary forms, with or without 612SN/A * modification, are permitted provided that the following conditions are 712SN/A * met: redistributions of source code must retain the above copyright 812SN/A * notice, this list of conditions and the following disclaimer; 912SN/A * redistributions in binary form must reproduce the above copyright 1012SN/A * notice, this list of conditions and the following disclaimer in the 1112SN/A * documentation and/or other materials provided with the distribution; 1212SN/A * neither the name of the copyright holders nor the names of its 1312SN/A * contributors may be used to endorse or promote products derived from 1412SN/A * this software without specific prior written permission. 1512SN/A * 1612SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 292665Ssaidi@eecs.umich.edu * Ali Saidi 3012SN/A */ 3112SN/A 3212SN/A#include <string> 3312SN/A 342634Sstever@eecs.umich.edu#include "gelf.h" 35468SN/A 3656SN/A#include "base/loader/elf_object.hh" 374484Sbinkertn@umich.edu#include "base/loader/symtab.hh" 382439SN/A#include "base/misc.hh" 3956SN/A#include "base/trace.hh" // for DPRINTF 402423SN/A#include "sim/byteswap.hh" 412423SN/A 4212SN/Ausing namespace std; 4312SN/A 4412SN/AObjectFile * 4512SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 4612SN/A{ 47443SN/A Elf *elf; 48443SN/A GElf_Ehdr ehdr; 492207SN/A Arch arch = UnknownArch; 502207SN/A OpSys opSys = UnknownOpSys; 51443SN/A 52468SN/A // check that header matches library version 531708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 541708SN/A panic("wrong elf version number!"); 55443SN/A 56468SN/A // get a pointer to elf structure 57443SN/A elf = elf_memory((char*)data,len); 58468SN/A // will only fail if fd is invalid 59443SN/A assert(elf != NULL); 60443SN/A 61468SN/A // Check that we actually have a elf file 62468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 63443SN/A DPRINTFR(Loader, "Not ELF\n"); 64443SN/A elf_end(elf); 65443SN/A return NULL; 662476SN/A } else { 672207SN/A //Detect the architecture 682207SN/A //Since we don't know how to check for alpha right now, we'll 692207SN/A //just assume if it wasn't something else and it's 64 bit, that's 702207SN/A //what it must be. 712207SN/A if (ehdr.e_machine == EM_SPARC64 || 724111Sgblack@eecs.umich.edu (ehdr.e_machine == EM_SPARC && 734111Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64)|| 742620SN/A ehdr.e_machine == EM_SPARCV9) { 754111Sgblack@eecs.umich.edu arch = ObjectFile::SPARC64; 764111Sgblack@eecs.umich.edu } else if (ehdr.e_machine == EM_SPARC32PLUS || 774111Sgblack@eecs.umich.edu (ehdr.e_machine == EM_SPARC && 784111Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { 794111Sgblack@eecs.umich.edu arch = ObjectFile::SPARC32; 802207SN/A } else if (ehdr.e_machine == EM_MIPS 812207SN/A && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 822472SN/A arch = ObjectFile::Mips; 834166Sgblack@eecs.umich.edu } else if (ehdr.e_machine == EM_X86_64 && 844166Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 854166Sgblack@eecs.umich.edu //In the future, we might want to differentiate between 32 bit 864166Sgblack@eecs.umich.edu //and 64 bit x86 processes in case there are differences in their 874166Sgblack@eecs.umich.edu //initial stack frame. 884166Sgblack@eecs.umich.edu arch = ObjectFile::X86; 892207SN/A } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 902207SN/A arch = ObjectFile::Alpha; 912207SN/A } else { 922600SN/A warn("Unknown architecture: %d\n", ehdr.e_machine); 932207SN/A arch = ObjectFile::UnknownArch; 942207SN/A } 952207SN/A 962207SN/A //Detect the operating system 972207SN/A switch (ehdr.e_ident[EI_OSABI]) 982207SN/A { 992238SN/A 1002207SN/A case ELFOSABI_LINUX: 1012207SN/A opSys = ObjectFile::Linux; 1022207SN/A break; 1032207SN/A case ELFOSABI_SOLARIS: 1042207SN/A opSys = ObjectFile::Solaris; 1052238SN/A break; 1062207SN/A case ELFOSABI_TRU64: 1072207SN/A opSys = ObjectFile::Tru64; 1082238SN/A break; 1092207SN/A default: 1102207SN/A opSys = ObjectFile::UnknownOpSys; 1112207SN/A } 1122207SN/A 1132238SN/A //take a look at the .note.ABI section 1142238SN/A //It can let us know what's what. 1152600SN/A if (opSys == ObjectFile::UnknownOpSys) { 1162238SN/A Elf_Scn *section; 1172238SN/A GElf_Shdr shdr; 1182238SN/A Elf_Data *data; 1192238SN/A uint32_t osAbi;; 1202238SN/A int secIdx = 1; 1212238SN/A 1222238SN/A // Get the first section 1232238SN/A section = elf_getscn(elf, secIdx); 1242238SN/A 1252238SN/A // While there are no more sections 1262600SN/A while (section != NULL && opSys == ObjectFile::UnknownOpSys) { 1272238SN/A gelf_getshdr(section, &shdr); 1282238SN/A if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1292238SN/A elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1302238SN/A // we have found a ABI note section 1312238SN/A // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1322238SN/A // 2 == solaris, 3 == freebsd 1332238SN/A data = elf_rawdata(section, NULL); 1342238SN/A assert(data->d_buf); 1352238SN/A if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1362238SN/A osAbi = htole(((uint32_t*)data->d_buf)[4]); 1372238SN/A else 1382238SN/A osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1392238SN/A 1402238SN/A switch(osAbi) { 1412238SN/A case 0: 1422238SN/A opSys = ObjectFile::Linux; 1432238SN/A break; 1442238SN/A case 2: 1452238SN/A opSys = ObjectFile::Solaris; 1462238SN/A break; 1472238SN/A } 1482238SN/A } // if section found 1492600SN/A if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1502600SN/A opSys = ObjectFile::Solaris; 1512600SN/A if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1522600SN/A opSys = ObjectFile::Solaris; 1532600SN/A 1542238SN/A section = elf_getscn(elf, ++secIdx); 1552238SN/A } // while sections 1562238SN/A } 1572472SN/A 1582976Sgblack@eecs.umich.edu ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys); 1592976Sgblack@eecs.umich.edu 1602976Sgblack@eecs.umich.edu //The number of headers in the file 1612976Sgblack@eecs.umich.edu result->_programHeaderCount = ehdr.e_phnum; 1622976Sgblack@eecs.umich.edu //Record the size of each entry 1632976Sgblack@eecs.umich.edu result->_programHeaderSize = ehdr.e_phentsize; 1642976Sgblack@eecs.umich.edu if(result->_programHeaderCount) //If there is a program header table 1652976Sgblack@eecs.umich.edu { 1662976Sgblack@eecs.umich.edu //Figure out the virtual address of the header table in the 1672976Sgblack@eecs.umich.edu //final memory image. We use the program headers themselves 1682976Sgblack@eecs.umich.edu //to translate from a file offset to the address in the image. 1692976Sgblack@eecs.umich.edu GElf_Phdr phdr; 1702976Sgblack@eecs.umich.edu uint64_t e_phoff = ehdr.e_phoff; 1712976Sgblack@eecs.umich.edu result->_programHeaderTable = 0; 1722976Sgblack@eecs.umich.edu for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++) 1732976Sgblack@eecs.umich.edu { 1742976Sgblack@eecs.umich.edu gelf_getphdr(elf, hdrnum, &phdr); 1752976Sgblack@eecs.umich.edu //Check if we've found the segment with the headers in it 1762976Sgblack@eecs.umich.edu if(phdr.p_offset <= e_phoff && 1772976Sgblack@eecs.umich.edu phdr.p_offset + phdr.p_filesz > e_phoff) 1782976Sgblack@eecs.umich.edu { 1795143Sgblack@eecs.umich.edu result->_programHeaderTable = phdr.p_paddr + e_phoff; 1802976Sgblack@eecs.umich.edu break; 1812976Sgblack@eecs.umich.edu } 1822976Sgblack@eecs.umich.edu } 1832976Sgblack@eecs.umich.edu } 1842976Sgblack@eecs.umich.edu else 1852976Sgblack@eecs.umich.edu result->_programHeaderTable = 0; 1862976Sgblack@eecs.umich.edu 1872976Sgblack@eecs.umich.edu 1882238SN/A elf_end(elf); 1892976Sgblack@eecs.umich.edu return result; 19012SN/A } 19112SN/A} 19212SN/A 19312SN/A 19412SN/AElfObject::ElfObject(const string &_filename, int _fd, 195360SN/A size_t _len, uint8_t *_data, 196360SN/A Arch _arch, OpSys _opSys) 197360SN/A : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 198443SN/A 19912SN/A{ 200443SN/A Elf *elf; 201443SN/A GElf_Ehdr ehdr; 20212SN/A 203468SN/A // check that header matches library version 2041708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 2051708SN/A panic("wrong elf version number!"); 20612SN/A 207468SN/A // get a pointer to elf structure 208443SN/A elf = elf_memory((char*)fileData,len); 209468SN/A // will only fail if fd is invalid 210443SN/A assert(elf != NULL); 21112SN/A 212468SN/A // Check that we actually have a elf file 213468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 214443SN/A panic("Not ELF, shouldn't be here"); 21512SN/A } 21612SN/A 217468SN/A entry = ehdr.e_entry; 21812SN/A 219468SN/A // initialize segment sizes to 0 in case they're not present 220468SN/A text.size = data.size = bss.size = 0; 221468SN/A 2225090Sgblack@eecs.umich.edu int secIdx = 1; 2235090Sgblack@eecs.umich.edu Elf_Scn *section; 2245090Sgblack@eecs.umich.edu GElf_Shdr shdr; 2255090Sgblack@eecs.umich.edu 2265090Sgblack@eecs.umich.edu // The first address of some important sections. 2275090Sgblack@eecs.umich.edu Addr textSecStart = 0; 2285090Sgblack@eecs.umich.edu Addr dataSecStart = 0; 2295090Sgblack@eecs.umich.edu Addr bssSecStart = 0; 2305090Sgblack@eecs.umich.edu 2315090Sgblack@eecs.umich.edu // Get the first section 2325090Sgblack@eecs.umich.edu section = elf_getscn(elf, secIdx); 2335090Sgblack@eecs.umich.edu 2345090Sgblack@eecs.umich.edu // Find the beginning of the most interesting sections. 2355090Sgblack@eecs.umich.edu while (section != NULL) { 2365090Sgblack@eecs.umich.edu gelf_getshdr(section, &shdr); 2375090Sgblack@eecs.umich.edu char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 2385090Sgblack@eecs.umich.edu 2395090Sgblack@eecs.umich.edu if (!strcmp(".text", secName)) { 2405090Sgblack@eecs.umich.edu textSecStart = shdr.sh_addr; 2415090Sgblack@eecs.umich.edu } else if (!strcmp(".data", secName)) { 2425090Sgblack@eecs.umich.edu dataSecStart = shdr.sh_addr; 2435090Sgblack@eecs.umich.edu } else if (!strcmp(".bss", secName)) { 2445090Sgblack@eecs.umich.edu bssSecStart = shdr.sh_addr; 2455090Sgblack@eecs.umich.edu } 2465090Sgblack@eecs.umich.edu 2475090Sgblack@eecs.umich.edu section = elf_getscn(elf, ++secIdx); 2485090Sgblack@eecs.umich.edu } 2495090Sgblack@eecs.umich.edu 2505090Sgblack@eecs.umich.edu // Go through all the segments in the program, record them, and scrape 2515090Sgblack@eecs.umich.edu // out information about the text, data, and bss areas needed by other 2525090Sgblack@eecs.umich.edu // code. 253468SN/A for (int i = 0; i < ehdr.e_phnum; ++i) { 254468SN/A GElf_Phdr phdr; 255468SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 2565090Sgblack@eecs.umich.edu panic("gelf_getphdr failed for segment %d.", i); 257468SN/A } 258468SN/A 259468SN/A // for now we don't care about non-loadable segments 260468SN/A if (!(phdr.p_type & PT_LOAD)) 261468SN/A continue; 262468SN/A 2635090Sgblack@eecs.umich.edu // Check to see if this segment contains the bss section. 2645143Sgblack@eecs.umich.edu if (phdr.p_paddr <= bssSecStart && 2655143Sgblack@eecs.umich.edu phdr.p_paddr + phdr.p_memsz > bssSecStart && 2665090Sgblack@eecs.umich.edu phdr.p_memsz - phdr.p_filesz > 0) { 2675143Sgblack@eecs.umich.edu bss.baseAddr = phdr.p_paddr + phdr.p_filesz; 2685090Sgblack@eecs.umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 2695090Sgblack@eecs.umich.edu bss.fileImage = NULL; 2705090Sgblack@eecs.umich.edu } 2715090Sgblack@eecs.umich.edu 2725090Sgblack@eecs.umich.edu // Check to see if this is the text or data segment 2735152Sgblack@eecs.umich.edu if (phdr.p_vaddr <= textSecStart && 2745152Sgblack@eecs.umich.edu phdr.p_vaddr + phdr.p_filesz > textSecStart) { 2755143Sgblack@eecs.umich.edu text.baseAddr = phdr.p_paddr; 276468SN/A text.size = phdr.p_filesz; 2772420SN/A text.fileImage = fileData + phdr.p_offset; 2785152Sgblack@eecs.umich.edu } else if (phdr.p_vaddr <= dataSecStart && 2795152Sgblack@eecs.umich.edu phdr.p_vaddr + phdr.p_filesz > dataSecStart) { 2805143Sgblack@eecs.umich.edu data.baseAddr = phdr.p_paddr; 281468SN/A data.size = phdr.p_filesz; 2822420SN/A data.fileImage = fileData + phdr.p_offset; 2832476SN/A } else { 2845090Sgblack@eecs.umich.edu Segment extra; 2855143Sgblack@eecs.umich.edu extra.baseAddr = phdr.p_paddr; 2865090Sgblack@eecs.umich.edu extra.size = phdr.p_filesz; 2875090Sgblack@eecs.umich.edu extra.fileImage = fileData + phdr.p_offset; 2885090Sgblack@eecs.umich.edu extraSegments.push_back(extra); 289468SN/A } 290468SN/A } 291468SN/A 292468SN/A // should have found at least one loadable segment 293468SN/A assert(text.size != 0); 294468SN/A 295468SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 296468SN/A text.baseAddr, text.size, data.baseAddr, data.size, 297468SN/A bss.baseAddr, bss.size); 298468SN/A 299443SN/A elf_end(elf); 300443SN/A 301468SN/A // We will actually read the sections when we need to load them 30212SN/A} 30312SN/A 30412SN/A 30512SN/Abool 306468SN/AElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 30712SN/A{ 308443SN/A Elf *elf; 309766SN/A int sec_idx = 1; // there is a 0 but it is nothing, go figure 310443SN/A Elf_Scn *section; 311443SN/A GElf_Shdr shdr; 312443SN/A Elf_Data *data; 313443SN/A int count, ii; 314443SN/A bool found = false; 315443SN/A GElf_Sym sym; 316443SN/A 317443SN/A if (!symtab) 318443SN/A return false; 319443SN/A 320468SN/A // check that header matches library version 3211708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 3221708SN/A panic("wrong elf version number!"); 323443SN/A 324468SN/A // get a pointer to elf structure 325443SN/A elf = elf_memory((char*)fileData,len); 326443SN/A 327443SN/A assert(elf != NULL); 328443SN/A 329468SN/A // Get the first section 330454SN/A section = elf_getscn(elf, sec_idx); 331443SN/A 332468SN/A // While there are no more sections 333468SN/A while (section != NULL) { 334443SN/A gelf_getshdr(section, &shdr); 335443SN/A 336468SN/A if (shdr.sh_type == SHT_SYMTAB) { 337443SN/A found = true; 338443SN/A data = elf_getdata(section, NULL); 339443SN/A count = shdr.sh_size / shdr.sh_entsize; 340443SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 341443SN/A 342468SN/A // loop through all the symbols, only loading global ones 343468SN/A for (ii = 0; ii < count; ++ii) { 344443SN/A gelf_getsym(data, ii, &sym); 345836SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 346468SN/A symtab->insert(sym.st_value, 347468SN/A elf_strptr(elf, shdr.sh_link, sym.st_name)); 348443SN/A } 349443SN/A } 350443SN/A } 351454SN/A ++sec_idx; 352454SN/A section = elf_getscn(elf, sec_idx); 353443SN/A } 354443SN/A 355443SN/A elf_end(elf); 356443SN/A 357443SN/A return found; 35812SN/A} 35912SN/A 36012SN/Abool 3613812Ssaidi@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) 362468SN/A{ 363468SN/A return loadSomeSymbols(symtab, STB_GLOBAL); 364468SN/A} 365468SN/A 366468SN/Abool 3673812Ssaidi@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) 36812SN/A{ 369468SN/A return loadSomeSymbols(symtab, STB_LOCAL); 37012SN/A} 3713917Ssaidi@eecs.umich.edu 3725090Sgblack@eecs.umich.edubool 3735090Sgblack@eecs.umich.eduElfObject::loadSections(Port *memPort, Addr addrMask) 3745090Sgblack@eecs.umich.edu{ 3755090Sgblack@eecs.umich.edu if (!ObjectFile::loadSections(memPort, addrMask)) 3765090Sgblack@eecs.umich.edu return false; 3775090Sgblack@eecs.umich.edu 3785090Sgblack@eecs.umich.edu vector<Segment>::iterator extraIt; 3795090Sgblack@eecs.umich.edu for (extraIt = extraSegments.begin(); 3805090Sgblack@eecs.umich.edu extraIt != extraSegments.end(); extraIt++) { 3815090Sgblack@eecs.umich.edu if (!loadSection(&(*extraIt), memPort, addrMask)) { 3825090Sgblack@eecs.umich.edu return false; 3835090Sgblack@eecs.umich.edu } 3845090Sgblack@eecs.umich.edu } 3855090Sgblack@eecs.umich.edu return true; 3865090Sgblack@eecs.umich.edu} 3875090Sgblack@eecs.umich.edu 3885070Ssaidi@eecs.umich.eduvoid 3895070Ssaidi@eecs.umich.eduElfObject::getSections() 3903917Ssaidi@eecs.umich.edu{ 3913917Ssaidi@eecs.umich.edu Elf *elf; 3923917Ssaidi@eecs.umich.edu int sec_idx = 1; // there is a 0 but it is nothing, go figure 3933917Ssaidi@eecs.umich.edu Elf_Scn *section; 3943917Ssaidi@eecs.umich.edu GElf_Shdr shdr; 3953917Ssaidi@eecs.umich.edu 3963917Ssaidi@eecs.umich.edu GElf_Ehdr ehdr; 3973917Ssaidi@eecs.umich.edu 3985070Ssaidi@eecs.umich.edu assert(!sectionNames.size()); 3995070Ssaidi@eecs.umich.edu 4003917Ssaidi@eecs.umich.edu // check that header matches library version 4013917Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 4023917Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 4033917Ssaidi@eecs.umich.edu 4043917Ssaidi@eecs.umich.edu // get a pointer to elf structure 4053917Ssaidi@eecs.umich.edu elf = elf_memory((char*)fileData,len); 4063917Ssaidi@eecs.umich.edu assert(elf != NULL); 4073917Ssaidi@eecs.umich.edu 4083917Ssaidi@eecs.umich.edu // Check that we actually have a elf file 4093917Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 4103917Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 4113917Ssaidi@eecs.umich.edu } 4123917Ssaidi@eecs.umich.edu 4133917Ssaidi@eecs.umich.edu // Get the first section 4143917Ssaidi@eecs.umich.edu section = elf_getscn(elf, sec_idx); 4153917Ssaidi@eecs.umich.edu 4163917Ssaidi@eecs.umich.edu // While there are no more sections 4173917Ssaidi@eecs.umich.edu while (section != NULL) { 4183917Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 4195070Ssaidi@eecs.umich.edu sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)); 4203917Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++sec_idx); 4213917Ssaidi@eecs.umich.edu } // while sections 4223917Ssaidi@eecs.umich.edu} 4233917Ssaidi@eecs.umich.edu 4245070Ssaidi@eecs.umich.edubool 4255070Ssaidi@eecs.umich.eduElfObject::sectionExists(string sec) 4265070Ssaidi@eecs.umich.edu{ 4275070Ssaidi@eecs.umich.edu if (!sectionNames.size()) 4285070Ssaidi@eecs.umich.edu getSections(); 4295070Ssaidi@eecs.umich.edu return sectionNames.find(sec) != sectionNames.end(); 4305070Ssaidi@eecs.umich.edu} 4313917Ssaidi@eecs.umich.edu 4325070Ssaidi@eecs.umich.edu 433