1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995 |
- /*
- * ELF file handling for TCC
- *
- * Copyright (c) 2001-2004 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "tcc.h"
- /* Define this to get some debug output during relocation processing. */
- #undef DEBUG_RELOC
- /********************************************************/
- /* global variables */
- ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
- ST_DATA Section *common_section;
- ST_DATA Section *cur_text_section; /* current section where function code is generated */
- #ifdef CONFIG_TCC_ASM
- ST_DATA Section *last_text_section; /* to handle .previous asm directive */
- #endif
- #ifdef CONFIG_TCC_BCHECK
- /* bound check related sections */
- ST_DATA Section *bounds_section; /* contains global data bound description */
- ST_DATA Section *lbounds_section; /* contains local data bound description */
- #endif
- /* symbol sections */
- ST_DATA Section *symtab_section, *strtab_section;
- /* debug sections */
- ST_DATA Section *stab_section, *stabstr_section;
- /* XXX: avoid static variable */
- static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
- /* ------------------------------------------------------------------------- */
- ST_FUNC void tccelf_new(TCCState *s)
- {
- /* no section zero */
- dynarray_add(&s->sections, &s->nb_sections, NULL);
- /* create standard sections */
- text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
- data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
- bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
- common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
- common_section->sh_num = SHN_COMMON;
- /* symbols are always generated for linking stage */
- symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
- ".strtab",
- ".hashtab", SHF_PRIVATE);
- strtab_section = symtab_section->link;
- s->symtab = symtab_section;
- /* private symbol table for dynamic symbols */
- s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
- ".dynstrtab",
- ".dynhashtab", SHF_PRIVATE);
- get_sym_attr(s, 0, 1);
- }
- #ifdef CONFIG_TCC_BCHECK
- ST_FUNC void tccelf_bounds_new(TCCState *s)
- {
- /* create bounds sections */
- bounds_section = new_section(s, ".bounds",
- SHT_PROGBITS, SHF_ALLOC);
- lbounds_section = new_section(s, ".lbounds",
- SHT_PROGBITS, SHF_ALLOC);
- }
- #endif
- ST_FUNC void tccelf_stab_new(TCCState *s)
- {
- stab_section = new_section(s, ".stab", SHT_PROGBITS, 0);
- stab_section->sh_entsize = sizeof(Stab_Sym);
- stabstr_section = new_section(s, ".stabstr", SHT_STRTAB, 0);
- put_elf_str(stabstr_section, "");
- stab_section->link = stabstr_section;
- /* put first entry */
- put_stabs("", 0, 0, 0, 0);
- }
- static void free_section(Section *s)
- {
- tcc_free(s->data);
- }
- ST_FUNC void tccelf_delete(TCCState *s1)
- {
- int i;
- /* free all sections */
- for(i = 1; i < s1->nb_sections; i++)
- free_section(s1->sections[i]);
- dynarray_reset(&s1->sections, &s1->nb_sections);
- for(i = 0; i < s1->nb_priv_sections; i++)
- free_section(s1->priv_sections[i]);
- dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
- /* free any loaded DLLs */
- #ifdef TCC_IS_NATIVE
- for ( i = 0; i < s1->nb_loaded_dlls; i++) {
- DLLReference *ref = s1->loaded_dlls[i];
- if ( ref->handle )
- # ifdef _WIN32
- FreeLibrary((HMODULE)ref->handle);
- # else
- dlclose(ref->handle);
- # endif
- }
- #endif
- /* free loaded dlls array */
- dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
- tcc_free(s1->sym_attrs);
- }
- ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
- {
- Section *sec;
- sec = tcc_mallocz(sizeof(Section) + strlen(name));
- strcpy(sec->name, name);
- sec->sh_type = sh_type;
- sec->sh_flags = sh_flags;
- switch(sh_type) {
- case SHT_HASH:
- case SHT_REL:
- case SHT_RELA:
- case SHT_DYNSYM:
- case SHT_SYMTAB:
- case SHT_DYNAMIC:
- sec->sh_addralign = 4;
- break;
- case SHT_STRTAB:
- sec->sh_addralign = 1;
- break;
- default:
- sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */
- break;
- }
- if (sh_flags & SHF_PRIVATE) {
- dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec);
- } else {
- sec->sh_num = s1->nb_sections;
- dynarray_add(&s1->sections, &s1->nb_sections, sec);
- }
- return sec;
- }
- ST_FUNC Section *new_symtab(TCCState *s1,
- const char *symtab_name, int sh_type, int sh_flags,
- const char *strtab_name,
- const char *hash_name, int hash_sh_flags)
- {
- Section *symtab, *strtab, *hash;
- int *ptr, nb_buckets;
- symtab = new_section(s1, symtab_name, sh_type, sh_flags);
- symtab->sh_entsize = sizeof(ElfW(Sym));
- strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags);
- put_elf_str(strtab, "");
- symtab->link = strtab;
- put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL);
- nb_buckets = 1;
- hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags);
- hash->sh_entsize = sizeof(int);
- symtab->hash = hash;
- hash->link = symtab;
- ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int));
- ptr[0] = nb_buckets;
- ptr[1] = 1;
- memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
- return symtab;
- }
- /* realloc section and set its content to zero */
- ST_FUNC void section_realloc(Section *sec, unsigned long new_size)
- {
- unsigned long size;
- unsigned char *data;
- size = sec->data_allocated;
- if (size == 0)
- size = 1;
- while (size < new_size)
- size = size * 2;
- data = tcc_realloc(sec->data, size);
- memset(data + sec->data_allocated, 0, size - sec->data_allocated);
- sec->data = data;
- sec->data_allocated = size;
- }
- /* reserve at least 'size' bytes aligned per 'align' in section
- 'sec' from current offset, and return the aligned offset */
- ST_FUNC size_t section_add(Section *sec, addr_t size, int align)
- {
- size_t offset, offset1;
- offset = (sec->data_offset + align - 1) & -align;
- offset1 = offset + size;
- if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated)
- section_realloc(sec, offset1);
- sec->data_offset = offset1;
- if (align > sec->sh_addralign)
- sec->sh_addralign = align;
- return offset;
- }
- /* reserve at least 'size' bytes in section 'sec' from
- sec->data_offset. */
- ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
- {
- size_t offset = section_add(sec, size, 1);
- return sec->data + offset;
- }
- /* reserve at least 'size' bytes from section start */
- ST_FUNC void section_reserve(Section *sec, unsigned long size)
- {
- if (size > sec->data_allocated)
- section_realloc(sec, size);
- if (size > sec->data_offset)
- sec->data_offset = size;
- }
- /* return a reference to a section, and create it if it does not
- exists */
- ST_FUNC Section *find_section(TCCState *s1, const char *name)
- {
- Section *sec;
- int i;
- for(i = 1; i < s1->nb_sections; i++) {
- sec = s1->sections[i];
- if (!strcmp(name, sec->name))
- return sec;
- }
- /* sections are created as PROGBITS */
- return new_section(s1, name, SHT_PROGBITS, SHF_ALLOC);
- }
- /* ------------------------------------------------------------------------- */
- ST_FUNC int put_elf_str(Section *s, const char *sym)
- {
- int offset, len;
- char *ptr;
- len = strlen(sym) + 1;
- offset = s->data_offset;
- ptr = section_ptr_add(s, len);
- memcpy(ptr, sym, len);
- return offset;
- }
- /* elf symbol hashing function */
- static unsigned long elf_hash(const unsigned char *name)
- {
- unsigned long h = 0, g;
- while (*name) {
- h = (h << 4) + *name++;
- g = h & 0xf0000000;
- if (g)
- h ^= g >> 24;
- h &= ~g;
- }
- return h;
- }
- /* rebuild hash table of section s */
- /* NOTE: we do factorize the hash table code to go faster */
- static void rebuild_hash(Section *s, unsigned int nb_buckets)
- {
- ElfW(Sym) *sym;
- int *ptr, *hash, nb_syms, sym_index, h;
- unsigned char *strtab;
- strtab = s->link->data;
- nb_syms = s->data_offset / sizeof(ElfW(Sym));
- s->hash->data_offset = 0;
- ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
- ptr[0] = nb_buckets;
- ptr[1] = nb_syms;
- ptr += 2;
- hash = ptr;
- memset(hash, 0, (nb_buckets + 1) * sizeof(int));
- ptr += nb_buckets + 1;
- sym = (ElfW(Sym) *)s->data + 1;
- for(sym_index = 1; sym_index < nb_syms; sym_index++) {
- if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
- h = elf_hash(strtab + sym->st_name) % nb_buckets;
- *ptr = hash[h];
- hash[h] = sym_index;
- } else {
- *ptr = 0;
- }
- ptr++;
- sym++;
- }
- }
- /* return the symbol number */
- ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
- int info, int other, int shndx, const char *name)
- {
- int name_offset, sym_index;
- int nbuckets, h;
- ElfW(Sym) *sym;
- Section *hs;
- sym = section_ptr_add(s, sizeof(ElfW(Sym)));
- if (name)
- name_offset = put_elf_str(s->link, name);
- else
- name_offset = 0;
- /* XXX: endianness */
- sym->st_name = name_offset;
- sym->st_value = value;
- sym->st_size = size;
- sym->st_info = info;
- sym->st_other = other;
- sym->st_shndx = shndx;
- sym_index = sym - (ElfW(Sym) *)s->data;
- hs = s->hash;
- if (hs) {
- int *ptr, *base;
- ptr = section_ptr_add(hs, sizeof(int));
- base = (int *)hs->data;
- /* only add global or weak symbols */
- if (ELFW(ST_BIND)(info) != STB_LOCAL) {
- /* add another hashing entry */
- nbuckets = base[0];
- h = elf_hash((unsigned char *) name) % nbuckets;
- *ptr = base[2 + h];
- base[2 + h] = sym_index;
- base[1]++;
- /* we resize the hash table */
- hs->nb_hashed_syms++;
- if (hs->nb_hashed_syms > 2 * nbuckets) {
- rebuild_hash(s, 2 * nbuckets);
- }
- } else {
- *ptr = 0;
- base[1]++;
- }
- }
- return sym_index;
- }
- /* find global ELF symbol 'name' and return its index. Return 0 if not
- found. */
- ST_FUNC int find_elf_sym(Section *s, const char *name)
- {
- ElfW(Sym) *sym;
- Section *hs;
- int nbuckets, sym_index, h;
- const char *name1;
- hs = s->hash;
- if (!hs)
- return 0;
- nbuckets = ((int *)hs->data)[0];
- h = elf_hash((unsigned char *) name) % nbuckets;
- sym_index = ((int *)hs->data)[2 + h];
- while (sym_index != 0) {
- sym = &((ElfW(Sym) *)s->data)[sym_index];
- name1 = (char *) s->link->data + sym->st_name;
- if (!strcmp(name, name1))
- return sym_index;
- sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];
- }
- return 0;
- }
- /* return elf symbol value, signal error if 'err' is nonzero */
- ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err)
- {
- int sym_index;
- ElfW(Sym) *sym;
- sym_index = find_elf_sym(s->symtab, name);
- sym = &((ElfW(Sym) *)s->symtab->data)[sym_index];
- if (!sym_index || sym->st_shndx == SHN_UNDEF) {
- if (err)
- tcc_error("%s not defined", name);
- return 0;
- }
- return sym->st_value;
- }
- /* return elf symbol value */
- LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name)
- {
- return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0);
- }
- #if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
- /* return elf symbol value or error */
- ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
- {
- return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1);
- }
- #endif
- /* add an elf symbol : check if it is already defined and patch
- it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
- ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
- int info, int other, int shndx, const char *name)
- {
- ElfW(Sym) *esym;
- int sym_bind, sym_index, sym_type, esym_bind;
- unsigned char sym_vis, esym_vis, new_vis;
- sym_bind = ELFW(ST_BIND)(info);
- sym_type = ELFW(ST_TYPE)(info);
- sym_vis = ELFW(ST_VISIBILITY)(other);
- sym_index = find_elf_sym(s, name);
- esym = &((ElfW(Sym) *)s->data)[sym_index];
- if (sym_index && esym->st_value == value && esym->st_size == size
- && esym->st_info == info && esym->st_other == other
- && esym->st_shndx == shndx)
- return sym_index;
- if (sym_bind != STB_LOCAL) {
- /* we search global or weak symbols */
- if (!sym_index)
- goto do_def;
- if (esym->st_shndx != SHN_UNDEF) {
- esym_bind = ELFW(ST_BIND)(esym->st_info);
- /* propagate the most constraining visibility */
- /* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */
- esym_vis = ELFW(ST_VISIBILITY)(esym->st_other);
- if (esym_vis == STV_DEFAULT) {
- new_vis = sym_vis;
- } else if (sym_vis == STV_DEFAULT) {
- new_vis = esym_vis;
- } else {
- new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis;
- }
- esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
- | new_vis;
- other = esym->st_other; /* in case we have to patch esym */
- if (shndx == SHN_UNDEF) {
- /* ignore adding of undefined symbol if the
- corresponding symbol is already defined */
- } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) {
- /* global overrides weak, so patch */
- goto do_patch;
- } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {
- /* weak is ignored if already global */
- } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) {
- /* keep first-found weak definition, ignore subsequents */
- } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) {
- /* ignore hidden symbols after */
- } else if ((esym->st_shndx == SHN_COMMON
- || esym->st_shndx == bss_section->sh_num)
- && (shndx < SHN_LORESERVE
- && shndx != bss_section->sh_num)) {
- /* data symbol gets precedence over common/bss */
- goto do_patch;
- } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) {
- /* data symbol keeps precedence over common/bss */
- } else if (s == tcc_state->dynsymtab_section) {
- /* we accept that two DLL define the same symbol */
- } else {
- #if 0
- printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
- sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis);
- #endif
- tcc_error_noabort("'%s' defined twice", name);
- }
- } else {
- do_patch:
- esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
- esym->st_shndx = shndx;
- new_undef_sym = 1;
- esym->st_value = value;
- esym->st_size = size;
- esym->st_other = other;
- }
- } else {
- do_def:
- sym_index = put_elf_sym(s, value, size,
- ELFW(ST_INFO)(sym_bind, sym_type), other,
- shndx, name);
- }
- return sym_index;
- }
- /* put relocation */
- ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
- int type, int symbol, addr_t addend)
- {
- char buf[256];
- Section *sr;
- ElfW_Rel *rel;
- sr = s->reloc;
- if (!sr) {
- /* if no relocation section, create it */
- snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
- /* if the symtab is allocated, then we consider the relocation
- are also */
- sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags);
- sr->sh_entsize = sizeof(ElfW_Rel);
- sr->link = symtab;
- sr->sh_info = s->sh_num;
- s->reloc = sr;
- }
- rel = section_ptr_add(sr, sizeof(ElfW_Rel));
- rel->r_offset = offset;
- rel->r_info = ELFW(R_INFO)(symbol, type);
- #if SHT_RELX == SHT_RELA
- rel->r_addend = addend;
- #else
- if (addend)
- tcc_error("non-zero addend on REL architecture");
- #endif
- }
- ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
- int type, int symbol)
- {
- put_elf_reloca(symtab, s, offset, type, symbol, 0);
- }
- /* Remove relocations for section S->reloc starting at oldrelocoffset
- that are to the same place, retaining the last of them. As side effect
- the relocations are sorted. Possibly reduces the number of relocs. */
- ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
- {
- Section *sr = s->reloc;
- ElfW_Rel *r, *dest;
- ssize_t a;
- ElfW(Addr) addr;
- if (oldrelocoffset + sizeof(*r) >= sr->data_offset)
- return;
- /* The relocs we're dealing with are the result of initializer parsing.
- So they will be mostly in order and there aren't many of them.
- Secondly we need a stable sort (which qsort isn't). We use
- a simple insertion sort. */
- for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) {
- ssize_t i = a - sizeof(*r);
- addr = ((ElfW_Rel*)(sr->data + a))->r_offset;
- for (; i >= (ssize_t)oldrelocoffset &&
- ((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) {
- ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a);
- *(ElfW_Rel*)(sr->data + a) = *(ElfW_Rel*)(sr->data + i);
- *(ElfW_Rel*)(sr->data + i) = tmp;
- }
- }
- r = (ElfW_Rel*)(sr->data + oldrelocoffset);
- dest = r;
- for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) {
- if (dest->r_offset != r->r_offset)
- dest++;
- *dest = *r;
- }
- sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r);
- }
- /* put stab debug information */
- ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
- unsigned long value)
- {
- Stab_Sym *sym;
- sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
- if (str) {
- sym->n_strx = put_elf_str(stabstr_section, str);
- } else {
- sym->n_strx = 0;
- }
- sym->n_type = type;
- sym->n_other = other;
- sym->n_desc = desc;
- sym->n_value = value;
- }
- ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc,
- unsigned long value, Section *sec, int sym_index)
- {
- put_stabs(str, type, other, desc, value);
- put_elf_reloc(symtab_section, stab_section,
- stab_section->data_offset - sizeof(unsigned int),
- R_DATA_32, sym_index);
- }
- ST_FUNC void put_stabn(int type, int other, int desc, int value)
- {
- put_stabs(NULL, type, other, desc, value);
- }
- ST_FUNC void put_stabd(int type, int other, int desc)
- {
- put_stabs(NULL, type, other, desc, 0);
- }
- ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc)
- {
- int n;
- struct sym_attr *tab;
- if (index >= s1->nb_sym_attrs) {
- if (!alloc)
- return s1->sym_attrs;
- /* find immediately bigger power of 2 and reallocate array */
- n = 1;
- while (index >= n)
- n *= 2;
- tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs));
- s1->sym_attrs = tab;
- memset(s1->sym_attrs + s1->nb_sym_attrs, 0,
- (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs));
- s1->nb_sym_attrs = n;
- }
- return &s1->sym_attrs[index];
- }
- /* Browse each elem of type <type> in section <sec> starting at elem <startoff>
- using variable <elem> */
- #define for_each_elem(sec, startoff, elem, type) \
- for (elem = (type *) sec->data + startoff; \
- elem < (type *) (sec->data + sec->data_offset); elem++)
- /* In an ELF file symbol table, the local symbols must appear below
- the global and weak ones. Since TCC cannot sort it while generating
- the code, we must do it after. All the relocation tables are also
- modified to take into account the symbol table sorting */
- static void sort_syms(TCCState *s1, Section *s)
- {
- int *old_to_new_syms;
- ElfW(Sym) *new_syms;
- int nb_syms, i;
- ElfW(Sym) *p, *q;
- ElfW_Rel *rel;
- Section *sr;
- int type, sym_index;
- nb_syms = s->data_offset / sizeof(ElfW(Sym));
- new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym)));
- old_to_new_syms = tcc_malloc(nb_syms * sizeof(int));
- /* first pass for local symbols */
- p = (ElfW(Sym) *)s->data;
- q = new_syms;
- for(i = 0; i < nb_syms; i++) {
- if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) {
- old_to_new_syms[i] = q - new_syms;
- *q++ = *p;
- }
- p++;
- }
- /* save the number of local symbols in section header */
- if( s->sh_size ) /* this 'if' makes IDA happy */
- s->sh_info = q - new_syms;
- /* then second pass for non local symbols */
- p = (ElfW(Sym) *)s->data;
- for(i = 0; i < nb_syms; i++) {
- if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) {
- old_to_new_syms[i] = q - new_syms;
- *q++ = *p;
- }
- p++;
- }
- /* we copy the new symbols to the old */
- memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym)));
- tcc_free(new_syms);
- /* now we modify all the relocations */
- for(i = 1; i < s1->nb_sections; i++) {
- sr = s1->sections[i];
- if (sr->sh_type == SHT_RELX && sr->link == s) {
- for_each_elem(sr, 0, rel, ElfW_Rel) {
- sym_index = ELFW(R_SYM)(rel->r_info);
- type = ELFW(R_TYPE)(rel->r_info);
- sym_index = old_to_new_syms[sym_index];
- rel->r_info = ELFW(R_INFO)(sym_index, type);
- }
- }
- }
- tcc_free(old_to_new_syms);
- }
- /* relocate common symbols in the .bss section */
- ST_FUNC void relocate_common_syms(void)
- {
- ElfW(Sym) *sym;
- for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
- if (sym->st_shndx == SHN_COMMON) {
- /* symbol alignment is in st_value for SHN_COMMONs */
- sym->st_value = section_add(bss_section, sym->st_size,
- sym->st_value);
- sym->st_shndx = bss_section->sh_num;
- }
- }
- }
- /* relocate symbol table, resolve undefined symbols if do_resolve is
- true and output error if undefined symbol. */
- ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
- {
- ElfW(Sym) *sym;
- int sym_bind, sh_num;
- const char *name;
- for_each_elem(symtab, 1, sym, ElfW(Sym)) {
- sh_num = sym->st_shndx;
- if (sh_num == SHN_UNDEF) {
- name = (char *) strtab_section->data + sym->st_name;
- /* Use ld.so to resolve symbol for us (for tcc -run) */
- if (do_resolve) {
- #if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
- void *addr = dlsym(RTLD_DEFAULT, name);
- if (addr) {
- sym->st_value = (addr_t) addr;
- #ifdef DEBUG_RELOC
- printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value);
- #endif
- goto found;
- }
- #endif
- /* if dynamic symbol exist, it will be used in relocate_section */
- } else if (s1->dynsym && find_elf_sym(s1->dynsym, name))
- goto found;
- /* XXX: _fp_hw seems to be part of the ABI, so we ignore
- it */
- if (!strcmp(name, "_fp_hw"))
- goto found;
- /* only weak symbols are accepted to be undefined. Their
- value is zero */
- sym_bind = ELFW(ST_BIND)(sym->st_info);
- if (sym_bind == STB_WEAK)
- sym->st_value = 0;
- else
- tcc_error_noabort("undefined symbol '%s'", name);
- } else if (sh_num < SHN_LORESERVE) {
- /* add section base */
- sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
- }
- found: ;
- }
- }
- /* relocate a given section (CPU dependent) by applying the relocations
- in the associated relocation section */
- ST_FUNC void relocate_section(TCCState *s1, Section *s)
- {
- Section *sr = s->reloc;
- ElfW_Rel *rel;
- ElfW(Sym) *sym;
- int type, sym_index;
- unsigned char *ptr;
- addr_t tgt, addr;
- relocate_init(sr);
- for_each_elem(sr, 0, rel, ElfW_Rel) {
- ptr = s->data + rel->r_offset;
- sym_index = ELFW(R_SYM)(rel->r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- type = ELFW(R_TYPE)(rel->r_info);
- tgt = sym->st_value;
- #if SHT_RELX == SHT_RELA
- tgt += rel->r_addend;
- #endif
- addr = s->sh_addr + rel->r_offset;
- relocate(s1, rel, type, ptr, addr, tgt);
- }
- /* if the relocation is allocated, we change its symbol table */
- if (sr->sh_flags & SHF_ALLOC)
- sr->link = s1->dynsym;
- }
- /* relocate relocation table in 'sr' */
- static void relocate_rel(TCCState *s1, Section *sr)
- {
- Section *s;
- ElfW_Rel *rel;
- s = s1->sections[sr->sh_info];
- for_each_elem(sr, 0, rel, ElfW_Rel)
- rel->r_offset += s->sh_addr;
- }
- /* count the number of dynamic relocations so that we can reserve
- their space */
- static int prepare_dynamic_rel(TCCState *s1, Section *sr)
- {
- ElfW_Rel *rel;
- int sym_index, type, count;
- count = 0;
- for_each_elem(sr, 0, rel, ElfW_Rel) {
- sym_index = ELFW(R_SYM)(rel->r_info);
- type = ELFW(R_TYPE)(rel->r_info);
- switch(type) {
- #if defined(TCC_TARGET_I386)
- case R_386_32:
- if (!get_sym_attr(s1, sym_index, 0)->dyn_index
- && ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) {
- /* don't fixup unresolved (weak) symbols */
- rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE);
- break;
- }
- #elif defined(TCC_TARGET_X86_64)
- case R_X86_64_32:
- case R_X86_64_32S:
- case R_X86_64_64:
- #endif
- count++;
- break;
- #if defined(TCC_TARGET_I386)
- case R_386_PC32:
- #elif defined(TCC_TARGET_X86_64)
- case R_X86_64_PC32:
- #endif
- if (get_sym_attr(s1, sym_index, 0)->dyn_index)
- count++;
- break;
- default:
- break;
- }
- }
- if (count) {
- /* allocate the section */
- sr->sh_flags |= SHF_ALLOC;
- sr->sh_size = count * sizeof(ElfW_Rel);
- }
- return count;
- }
- static void build_got(TCCState *s1)
- {
- /* if no got, then create it */
- s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
- s1->got->sh_entsize = 4;
- set_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT),
- 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_");
- /* keep space for _DYNAMIC pointer and two dummy got entries */
- section_ptr_add(s1->got, 3 * PTR_SIZE);
- }
- /* Create a GOT and (for function call) a PLT entry corresponding to a symbol
- in s1->symtab. When creating the dynamic symbol table entry for the GOT
- relocation, use 'size' and 'info' for the corresponding symbol metadata.
- Returns the offset of the GOT or (if any) PLT entry. */
- static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
- unsigned long size,
- int info, int sym_index)
- {
- int need_plt_entry;
- const char *name;
- ElfW(Sym) *sym;
- struct sym_attr *attr;
- unsigned got_offset;
- char plt_name[100];
- int len;
- need_plt_entry = (dyn_reloc_type == R_JMP_SLOT);
- attr = get_sym_attr(s1, sym_index, 1);
- /* In case a function is both called and its address taken 2 GOT entries
- are created, one for taking the address (GOT) and the other for the PLT
- entry (PLTGOT). */
- if (need_plt_entry ? attr->plt_offset : attr->got_offset)
- return attr;
- /* create the GOT entry */
- got_offset = s1->got->data_offset;
- section_ptr_add(s1->got, PTR_SIZE);
- /* Create the GOT relocation that will insert the address of the object or
- function of interest in the GOT entry. This is a static relocation for
- memory output (dlsym will give us the address of symbols) and dynamic
- relocation otherwise (executable and DLLs). The relocation should be
- done lazily for GOT entry with *_JUMP_SLOT relocation type (the one
- associated to a PLT entry) but is currently done at load time for an
- unknown reason. */
- sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
- name = (char *) symtab_section->link->data + sym->st_name;
- if (s1->dynsym) {
- if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
- /* Hack alarm. We don't want to emit dynamic symbols
- and symbol based relocs for STB_LOCAL symbols, but rather
- want to resolve them directly. At this point the symbol
- values aren't final yet, so we must defer this. We will later
- have to create a RELATIVE reloc anyway, so we misuse the
- relocation slot to smuggle the symbol reference until
- fill_local_got_entries. Not that the sym_index is
- relative to symtab_section, not s1->dynsym! Nevertheless
- we use s1->dyn_sym so that if this is the first call
- that got->reloc is correctly created. Also note that
- RELATIVE relocs are not normally created for the .got,
- so the types serves as a marker for later (and is retained
- also for the final output, which is okay because then the
- got is just normal data). */
- put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE,
- sym_index);
- } else {
- if (0 == attr->dyn_index)
- attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, size,
- info, 0, sym->st_shndx, name);
- put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
- attr->dyn_index);
- }
- } else {
- put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type,
- sym_index);
- }
- if (need_plt_entry) {
- if (!s1->plt) {
- s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
- SHF_ALLOC | SHF_EXECINSTR);
- s1->plt->sh_entsize = 4;
- }
- attr->plt_offset = create_plt_entry(s1, got_offset, attr);
- /* create a symbol 'sym@plt' for the PLT jump vector */
- len = strlen(name);
- if (len > sizeof plt_name - 5)
- len = sizeof plt_name - 5;
- memcpy(plt_name, name, len);
- strcpy(plt_name + len, "@plt");
- attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, sym->st_size,
- ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name);
- } else {
- attr->got_offset = got_offset;
- }
- return attr;
- }
- /* build GOT and PLT entries */
- ST_FUNC void build_got_entries(TCCState *s1)
- {
- Section *s;
- ElfW_Rel *rel;
- ElfW(Sym) *sym;
- int i, type, gotplt_entry, reloc_type, sym_index;
- struct sym_attr *attr;
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (s->sh_type != SHT_RELX)
- continue;
- /* no need to handle got relocations */
- if (s->link != symtab_section)
- continue;
- for_each_elem(s, 0, rel, ElfW_Rel) {
- type = ELFW(R_TYPE)(rel->r_info);
- gotplt_entry = gotplt_entry_type(type);
- sym_index = ELFW(R_SYM)(rel->r_info);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if (gotplt_entry == NO_GOTPLT_ENTRY) {
- continue;
- }
- /* Automatically create PLT/GOT [entry] if it is an undefined
- reference (resolved at runtime), or the symbol is absolute,
- probably created by tcc_add_symbol, and thus on 64-bit
- targets might be too far from application code. */
- if (gotplt_entry == AUTO_GOTPLT_ENTRY) {
- if (sym->st_shndx == SHN_UNDEF) {
- ElfW(Sym) *esym;
- int dynindex;
- if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT)
- continue;
- /* Relocations for UNDEF symbols would normally need
- to be transferred into the executable or shared object.
- If that were done AUTO_GOTPLT_ENTRY wouldn't exist.
- But TCC doesn't do that (at least for exes), so we
- need to resolve all such relocs locally. And that
- means PLT slots for functions in DLLs and COPY relocs for
- data symbols. COPY relocs were generated in
- bind_exe_dynsyms (and the symbol adjusted to be defined),
- and for functions we were generated a dynamic symbol
- of function type. */
- if (s1->dynsym) {
- /* dynsym isn't set for -run :-/ */
- dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index;
- esym = (ElfW(Sym) *)s1->dynsym->data + dynindex;
- if (dynindex
- && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC
- || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE
- && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
- goto jmp_slot;
- }
- } else if (!(sym->st_shndx == SHN_ABS
- #ifndef TCC_TARGET_ARM
- && PTR_SIZE == 8
- #endif
- ))
- continue;
- }
- #ifdef TCC_TARGET_X86_64
- if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) &&
- (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
- ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)) {
- rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
- continue;
- }
- #endif
- if (code_reloc(type)) {
- jmp_slot:
- reloc_type = R_JMP_SLOT;
- } else
- reloc_type = R_GLOB_DAT;
- if (!s1->got)
- build_got(s1);
- if (gotplt_entry == BUILD_GOT_ONLY)
- continue;
- attr = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
- sym_index);
- if (reloc_type == R_JMP_SLOT)
- rel->r_info = ELFW(R_INFO)(attr->plt_sym, type);
- }
- }
- }
- /* put dynamic tag */
- static void put_dt(Section *dynamic, int dt, addr_t val)
- {
- ElfW(Dyn) *dyn;
- dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn)));
- dyn->d_tag = dt;
- dyn->d_un.d_val = val;
- }
- #ifndef TCC_TARGET_PE
- static void add_init_array_defines(TCCState *s1, const char *section_name)
- {
- Section *s;
- long end_offset;
- char sym_start[1024];
- char sym_end[1024];
- snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
- snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
- s = find_section(s1, section_name);
- if (!s) {
- end_offset = 0;
- s = data_section;
- } else {
- end_offset = s->data_offset;
- }
- set_elf_sym(symtab_section,
- 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, sym_start);
- set_elf_sym(symtab_section,
- end_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, sym_end);
- }
- #endif
- static int tcc_add_support(TCCState *s1, const char *filename)
- {
- char buf[1024];
- snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename);
- return tcc_add_file(s1, buf);
- }
- ST_FUNC void tcc_add_bcheck(TCCState *s1)
- {
- #ifdef CONFIG_TCC_BCHECK
- addr_t *ptr;
- int sym_index;
- if (0 == s1->do_bounds_check)
- return;
- /* XXX: add an object file to do that */
- ptr = section_ptr_add(bounds_section, sizeof(*ptr));
- *ptr = 0;
- set_elf_sym(symtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- bounds_section->sh_num, "__bounds_start");
- /* pull bcheck.o from libtcc1.a */
- sym_index = set_elf_sym(symtab_section, 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- SHN_UNDEF, "__bound_init");
- if (s1->output_type != TCC_OUTPUT_MEMORY) {
- /* add 'call __bound_init()' in .init section */
- Section *init_section = find_section(s1, ".init");
- unsigned char *pinit = section_ptr_add(init_section, 5);
- pinit[0] = 0xe8;
- write32le(pinit + 1, -4);
- put_elf_reloc(symtab_section, init_section,
- init_section->data_offset - 4, R_386_PC32, sym_index);
- /* R_386_PC32 = R_X86_64_PC32 = 2 */
- }
- #endif
- }
- /* add tcc runtime libraries */
- ST_FUNC void tcc_add_runtime(TCCState *s1)
- {
- tcc_add_bcheck(s1);
- tcc_add_pragma_libs(s1);
- /* add libc */
- if (!s1->nostdlib) {
- tcc_add_library_err(s1, "c");
- #ifdef TCC_LIBGCC
- if (!s1->static_link) {
- if (TCC_LIBGCC[0] == '/')
- tcc_add_file(s1, TCC_LIBGCC);
- else
- tcc_add_dll(s1, TCC_LIBGCC, 0);
- }
- #endif
- tcc_add_support(s1, TCC_LIBTCC1);
- /* add crt end if not memory output */
- if (s1->output_type != TCC_OUTPUT_MEMORY)
- tcc_add_crt(s1, "crtn.o");
- }
- }
- /* add various standard linker symbols (must be done after the
- sections are filled (for example after allocating common
- symbols)) */
- ST_FUNC void tcc_add_linker_symbols(TCCState *s1)
- {
- char buf[1024];
- int i;
- Section *s;
- set_elf_sym(symtab_section,
- text_section->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- text_section->sh_num, "_etext");
- set_elf_sym(symtab_section,
- data_section->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- data_section->sh_num, "_edata");
- set_elf_sym(symtab_section,
- bss_section->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- bss_section->sh_num, "_end");
- #ifndef TCC_TARGET_PE
- /* horrible new standard ldscript defines */
- add_init_array_defines(s1, ".preinit_array");
- add_init_array_defines(s1, ".init_array");
- add_init_array_defines(s1, ".fini_array");
- #endif
- /* add start and stop symbols for sections whose name can be
- expressed in C */
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (s->sh_type == SHT_PROGBITS &&
- (s->sh_flags & SHF_ALLOC)) {
- const char *p;
- int ch;
- /* check if section name can be expressed in C */
- p = s->name;
- for(;;) {
- ch = *p;
- if (!ch)
- break;
- if (!isid(ch) && !isnum(ch))
- goto next_sec;
- p++;
- }
- snprintf(buf, sizeof(buf), "__start_%s", s->name);
- set_elf_sym(symtab_section,
- 0, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, buf);
- snprintf(buf, sizeof(buf), "__stop_%s", s->name);
- set_elf_sym(symtab_section,
- s->data_offset, 0,
- ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
- s->sh_num, buf);
- }
- next_sec: ;
- }
- }
- static void tcc_output_binary(TCCState *s1, FILE *f,
- const int *sec_order)
- {
- Section *s;
- int i, offset, size;
- offset = 0;
- for(i=1;i<s1->nb_sections;i++) {
- s = s1->sections[sec_order[i]];
- if (s->sh_type != SHT_NOBITS &&
- (s->sh_flags & SHF_ALLOC)) {
- while (offset < s->sh_offset) {
- fputc(0, f);
- offset++;
- }
- size = s->sh_size;
- fwrite(s->data, 1, size, f);
- offset += size;
- }
- }
- }
- ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
- {
- int sym_index = ELFW(R_SYM) (rel->r_info);
- ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
- struct sym_attr *attr = get_sym_attr(s1, sym_index, 0);
- unsigned offset = attr->got_offset;
- if (0 == offset)
- return;
- section_reserve(s1->got, offset + PTR_SIZE);
- #ifdef TCC_TARGET_X86_64
- write64le(s1->got->data + offset, sym->st_value);
- #else
- write32le(s1->got->data + offset, sym->st_value);
- #endif
- }
- /* Perform relocation to GOT or PLT entries */
- ST_FUNC void fill_got(TCCState *s1)
- {
- Section *s;
- ElfW_Rel *rel;
- int i;
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (s->sh_type != SHT_RELX)
- continue;
- /* no need to handle got relocations */
- if (s->link != symtab_section)
- continue;
- for_each_elem(s, 0, rel, ElfW_Rel) {
- switch (ELFW(R_TYPE) (rel->r_info)) {
- case R_X86_64_GOT32:
- case R_X86_64_GOTPCREL:
- case R_X86_64_GOTPCRELX:
- case R_X86_64_REX_GOTPCRELX:
- case R_X86_64_PLT32:
- fill_got_entry(s1, rel);
- break;
- }
- }
- }
- }
- /* See put_got_entry for a description. This is the second stage
- where GOT references to local defined symbols are rewritten. */
- static void fill_local_got_entries(TCCState *s1)
- {
- ElfW_Rel *rel;
- for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) {
- if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) {
- int sym_index = ELFW(R_SYM) (rel->r_info);
- ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
- struct sym_attr *attr = get_sym_attr(s1, sym_index, 0);
- unsigned offset = attr->got_offset;
- if (offset != rel->r_offset - s1->got->sh_addr)
- tcc_error_noabort("huh");
- rel->r_info = ELFW(R_INFO)(0, R_RELATIVE);
- #if SHT_RELX == SHT_RELA
- rel->r_addend = sym->st_value;
- #else
- /* All our REL architectures also happen to be 32bit LE. */
- write32le(s1->got->data + offset, sym->st_value);
- #endif
- }
- }
- }
- /* Bind symbols of executable: resolve undefined symbols from exported symbols
- in shared libraries and export non local defined symbols to shared libraries
- if -rdynamic switch was given on command line */
- static void bind_exe_dynsyms(TCCState *s1)
- {
- const char *name;
- int sym_index, index;
- ElfW(Sym) *sym, *esym;
- int type;
- /* Resolve undefined symbols from dynamic symbols. When there is a match:
- - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT
- - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */
- for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
- if (sym->st_shndx == SHN_UNDEF) {
- name = (char *) symtab_section->link->data + sym->st_name;
- sym_index = find_elf_sym(s1->dynsymtab_section, name);
- if (sym_index) {
- esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index];
- type = ELFW(ST_TYPE)(esym->st_info);
- if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) {
- /* Indirect functions shall have STT_FUNC type in executable
- * dynsym section. Indeed, a dlsym call following a lazy
- * resolution would pick the symbol value from the
- * executable dynsym entry which would contain the address
- * of the function wanted by the caller of dlsym instead of
- * the address of the function that would return that
- * address */
- int dynindex
- = put_elf_sym(s1->dynsym, 0, esym->st_size,
- ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
- name);
- int index = sym - (ElfW(Sym) *) symtab_section->data;
- get_sym_attr(s1, index, 1)->dyn_index = dynindex;
- } else if (type == STT_OBJECT) {
- unsigned long offset;
- ElfW(Sym) *dynsym;
- offset = bss_section->data_offset;
- /* XXX: which alignment ? */
- offset = (offset + 16 - 1) & -16;
- set_elf_sym (s1->symtab, offset, esym->st_size,
- esym->st_info, 0, bss_section->sh_num, name);
- index = put_elf_sym(s1->dynsym, offset, esym->st_size,
- esym->st_info, 0, bss_section->sh_num,
- name);
- /* Ensure R_COPY works for weak symbol aliases */
- if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) {
- for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) {
- if ((dynsym->st_value == esym->st_value)
- && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) {
- char *dynname = (char *) s1->dynsymtab_section->link->data
- + dynsym->st_name;
- put_elf_sym(s1->dynsym, offset, dynsym->st_size,
- dynsym->st_info, 0,
- bss_section->sh_num, dynname);
- break;
- }
- }
- }
- put_elf_reloc(s1->dynsym, bss_section,
- offset, R_COPY, index);
- offset += esym->st_size;
- bss_section->data_offset = offset;
- }
- } else {
- /* STB_WEAK undefined symbols are accepted */
- /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */
- if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
- !strcmp(name, "_fp_hw")) {
- } else {
- tcc_error_noabort("undefined symbol '%s'", name);
- }
- }
- } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
- /* if -rdynamic option, then export all non local symbols */
- name = (char *) symtab_section->link->data + sym->st_name;
- set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
- 0, sym->st_shndx, name);
- }
- }
- }
- /* Bind symbols of libraries: export all non local symbols of executable that
- are referenced by shared libraries. The reason is that the dynamic loader
- search symbol first in executable and then in libraries. Therefore a
- reference to a symbol already defined by a library can still be resolved by
- a symbol in the executable. */
- static void bind_libs_dynsyms(TCCState *s1)
- {
- const char *name;
- int sym_index;
- ElfW(Sym) *sym, *esym;
- for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) {
- name = (char *) s1->dynsymtab_section->link->data + esym->st_name;
- sym_index = find_elf_sym(symtab_section, name);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if (sym_index && sym->st_shndx != SHN_UNDEF
- && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
- set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
- sym->st_info, 0, sym->st_shndx, name);
- } else if (esym->st_shndx == SHN_UNDEF) {
- /* weak symbols can stay undefined */
- if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
- tcc_warning("undefined dynamic symbol '%s'", name);
- }
- }
- }
- /* Export all non local symbols. This is used by shared libraries so that the
- non local symbols they define can resolve a reference in another shared
- library or in the executable. Correspondingly, it allows undefined local
- symbols to be resolved by other shared libraries or by the executable. */
- static void export_global_syms(TCCState *s1)
- {
- int dynindex, index;
- const char *name;
- ElfW(Sym) *sym;
- for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
- if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
- name = (char *) symtab_section->link->data + sym->st_name;
- dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
- sym->st_info, 0, sym->st_shndx, name);
- index = sym - (ElfW(Sym) *) symtab_section->data;
- get_sym_attr(s1, index, 1)->dyn_index = dynindex;
- }
- }
- }
- /* Allocate strings for section names and decide if an unallocated section
- should be output.
- NOTE: the strsec section comes last, so its size is also correct ! */
- static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
- {
- int i;
- Section *s;
- int textrel = 0;
- /* Allocate strings for section names */
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- /* when generating a DLL, we include relocations but we may
- patch them */
- if (file_type == TCC_OUTPUT_DLL &&
- s->sh_type == SHT_RELX &&
- !(s->sh_flags & SHF_ALLOC) &&
- (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
- prepare_dynamic_rel(s1, s)) {
- if (s1->sections[s->sh_info]->sh_flags & SHF_EXECINSTR)
- textrel = 1;
- } else if (s1->do_debug ||
- file_type == TCC_OUTPUT_OBJ ||
- (s->sh_flags & SHF_ALLOC) ||
- i == (s1->nb_sections - 1)) {
- /* we output all sections if debug or object file */
- s->sh_size = s->data_offset;
- }
- if (s->sh_size || (s->sh_flags & SHF_ALLOC))
- s->sh_name = put_elf_str(strsec, s->name);
- }
- strsec->sh_size = strsec->data_offset;
- return textrel;
- }
- /* Info to be copied in dynamic section */
- struct dyn_inf {
- Section *dynamic;
- Section *dynstr;
- unsigned long data_offset;
- addr_t rel_addr;
- addr_t rel_size;
- #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- addr_t bss_addr;
- addr_t bss_size;
- #endif
- };
- /* Assign sections to segments and decide how are sections laid out when loaded
- in memory. This function also fills corresponding program headers. */
- static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
- Section *interp, Section* strsec,
- struct dyn_inf *dyninf, int *sec_order)
- {
- int i, j, k, file_type, sh_order_index, file_offset;
- unsigned long s_align;
- long long tmp;
- addr_t addr;
- ElfW(Phdr) *ph;
- Section *s;
- file_type = s1->output_type;
- sh_order_index = 1;
- file_offset = 0;
- if (s1->output_format == TCC_OUTPUT_FORMAT_ELF)
- file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
- s_align = ELF_PAGE_SIZE;
- if (s1->section_align)
- s_align = s1->section_align;
- if (phnum > 0) {
- if (s1->has_text_addr) {
- int a_offset, p_offset;
- addr = s1->text_addr;
- /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset %
- ELF_PAGE_SIZE */
- a_offset = (int) (addr & (s_align - 1));
- p_offset = file_offset & (s_align - 1);
- if (a_offset < p_offset)
- a_offset += s_align;
- file_offset += (a_offset - p_offset);
- } else {
- if (file_type == TCC_OUTPUT_DLL)
- addr = 0;
- else
- addr = ELF_START_ADDR;
- /* compute address after headers */
- addr += (file_offset & (s_align - 1));
- }
- ph = &phdr[0];
- /* Leave one program headers for the program interpreter and one for
- the program header table itself if needed. These are done later as
- they require section layout to be done first. */
- if (interp)
- ph += 2;
- /* dynamic relocation table information, for .dynamic section */
- dyninf->rel_addr = dyninf->rel_size = 0;
- #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- dyninf->bss_addr = dyninf->bss_size = 0;
- #endif
- for(j = 0; j < 2; j++) {
- ph->p_type = PT_LOAD;
- if (j == 0)
- ph->p_flags = PF_R | PF_X;
- else
- ph->p_flags = PF_R | PF_W;
- ph->p_align = s_align;
- /* Decide the layout of sections loaded in memory. This must
- be done before program headers are filled since they contain
- info about the layout. We do the following ordering: interp,
- symbol tables, relocations, progbits, nobits */
- /* XXX: do faster and simpler sorting */
- for(k = 0; k < 5; k++) {
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- /* compute if section should be included */
- if (j == 0) {
- if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) !=
- SHF_ALLOC)
- continue;
- } else {
- if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) !=
- (SHF_ALLOC | SHF_WRITE))
- continue;
- }
- if (s == interp) {
- if (k != 0)
- continue;
- } else if (s->sh_type == SHT_DYNSYM ||
- s->sh_type == SHT_STRTAB ||
- s->sh_type == SHT_HASH) {
- if (k != 1)
- continue;
- } else if (s->sh_type == SHT_RELX) {
- if (k != 2)
- continue;
- } else if (s->sh_type == SHT_NOBITS) {
- if (k != 4)
- continue;
- } else {
- if (k != 3)
- continue;
- }
- sec_order[sh_order_index++] = i;
- /* section matches: we align it and add its size */
- tmp = addr;
- addr = (addr + s->sh_addralign - 1) &
- ~(s->sh_addralign - 1);
- file_offset += (int) ( addr - tmp );
- s->sh_offset = file_offset;
- s->sh_addr = addr;
- /* update program header infos */
- if (ph->p_offset == 0) {
- ph->p_offset = file_offset;
- ph->p_vaddr = addr;
- ph->p_paddr = ph->p_vaddr;
- }
- /* update dynamic relocation infos */
- if (s->sh_type == SHT_RELX) {
- #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- if (!strcmp(strsec->data + s->sh_name, ".rel.got")) {
- dyninf->rel_addr = addr;
- dyninf->rel_size += s->sh_size; /* XXX only first rel. */
- }
- if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) {
- dyninf->bss_addr = addr;
- dyninf->bss_size = s->sh_size; /* XXX only first rel. */
- }
- #else
- if (dyninf->rel_size == 0)
- dyninf->rel_addr = addr;
- dyninf->rel_size += s->sh_size;
- #endif
- }
- addr += s->sh_size;
- if (s->sh_type != SHT_NOBITS)
- file_offset += s->sh_size;
- }
- }
- if (j == 0) {
- /* Make the first PT_LOAD segment include the program
- headers itself (and the ELF header as well), it'll
- come out with same memory use but will make various
- tools like binutils strip work better. */
- ph->p_offset &= ~(ph->p_align - 1);
- ph->p_vaddr &= ~(ph->p_align - 1);
- ph->p_paddr &= ~(ph->p_align - 1);
- }
- ph->p_filesz = file_offset - ph->p_offset;
- ph->p_memsz = addr - ph->p_vaddr;
- ph++;
- if (j == 0) {
- if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
- /* if in the middle of a page, we duplicate the page in
- memory so that one copy is RX and the other is RW */
- if ((addr & (s_align - 1)) != 0)
- addr += s_align;
- } else {
- addr = (addr + s_align - 1) & ~(s_align - 1);
- file_offset = (file_offset + s_align - 1) & ~(s_align - 1);
- }
- }
- }
- }
- /* all other sections come after */
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if (phnum > 0 && (s->sh_flags & SHF_ALLOC))
- continue;
- sec_order[sh_order_index++] = i;
- file_offset = (file_offset + s->sh_addralign - 1) &
- ~(s->sh_addralign - 1);
- s->sh_offset = file_offset;
- if (s->sh_type != SHT_NOBITS)
- file_offset += s->sh_size;
- }
- return file_offset;
- }
- static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
- Section *dynamic)
- {
- ElfW(Phdr) *ph;
- /* if interpreter, then add corresponding program header */
- if (interp) {
- ph = &phdr[0];
- ph->p_type = PT_PHDR;
- ph->p_offset = sizeof(ElfW(Ehdr));
- ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr));
- ph->p_vaddr = interp->sh_addr - ph->p_filesz;
- ph->p_paddr = ph->p_vaddr;
- ph->p_flags = PF_R | PF_X;
- ph->p_align = 4; /* interp->sh_addralign; */
- ph++;
- ph->p_type = PT_INTERP;
- ph->p_offset = interp->sh_offset;
- ph->p_vaddr = interp->sh_addr;
- ph->p_paddr = ph->p_vaddr;
- ph->p_filesz = interp->sh_size;
- ph->p_memsz = interp->sh_size;
- ph->p_flags = PF_R;
- ph->p_align = interp->sh_addralign;
- }
- /* if dynamic section, then add corresponding program header */
- if (dynamic) {
- ph = &phdr[phnum - 1];
- ph->p_type = PT_DYNAMIC;
- ph->p_offset = dynamic->sh_offset;
- ph->p_vaddr = dynamic->sh_addr;
- ph->p_paddr = ph->p_vaddr;
- ph->p_filesz = dynamic->sh_size;
- ph->p_memsz = dynamic->sh_size;
- ph->p_flags = PF_R | PF_W;
- ph->p_align = dynamic->sh_addralign;
- }
- }
- /* Fill the dynamic section with tags describing the address and size of
- sections */
- static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
- {
- Section *dynamic = dyninf->dynamic;
- /* put dynamic section entries */
- put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
- put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr);
- put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
- put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset);
- put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));
- #if PTR_SIZE == 8
- put_dt(dynamic, DT_RELA, dyninf->rel_addr);
- put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
- put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
- #else
- #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
- put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size);
- put_dt(dynamic, DT_JMPREL, dyninf->rel_addr);
- put_dt(dynamic, DT_PLTREL, DT_REL);
- put_dt(dynamic, DT_REL, dyninf->bss_addr);
- put_dt(dynamic, DT_RELSZ, dyninf->bss_size);
- #else
- put_dt(dynamic, DT_REL, dyninf->rel_addr);
- put_dt(dynamic, DT_RELSZ, dyninf->rel_size);
- put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
- #endif
- #endif
- if (s1->do_debug)
- put_dt(dynamic, DT_DEBUG, 0);
- put_dt(dynamic, DT_NULL, 0);
- }
- /* Relocate remaining sections and symbols (that is those not related to
- dynamic linking) */
- static int final_sections_reloc(TCCState *s1)
- {
- int i;
- Section *s;
- relocate_syms(s1, s1->symtab, 0);
- if (s1->nb_errors != 0)
- return -1;
- /* relocate sections */
- /* XXX: ignore sections with allocated relocations ? */
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- #if defined(TCC_TARGET_I386) || defined(TCC_MUSL)
- if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr
- /* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC
- checking is removed */
- #else
- if (s->reloc && s != s1->got)
- /* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */
- #endif
- relocate_section(s1, s);
- }
- /* relocate relocation entries if the relocation tables are
- allocated in the executable */
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[i];
- if ((s->sh_flags & SHF_ALLOC) &&
- s->sh_type == SHT_RELX) {
- relocate_rel(s1, s);
- }
- }
- return 0;
- }
- /* Create an ELF file on disk.
- This function handle ELF specific layout requirements */
- static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
- int file_offset, int *sec_order)
- {
- int i, shnum, offset, size, file_type;
- Section *s;
- ElfW(Ehdr) ehdr;
- ElfW(Shdr) shdr, *sh;
- file_type = s1->output_type;
- shnum = s1->nb_sections;
- memset(&ehdr, 0, sizeof(ehdr));
- if (phnum > 0) {
- ehdr.e_phentsize = sizeof(ElfW(Phdr));
- ehdr.e_phnum = phnum;
- ehdr.e_phoff = sizeof(ElfW(Ehdr));
- }
- /* align to 4 */
- file_offset = (file_offset + 3) & -4;
- /* fill header */
- ehdr.e_ident[0] = ELFMAG0;
- ehdr.e_ident[1] = ELFMAG1;
- ehdr.e_ident[2] = ELFMAG2;
- ehdr.e_ident[3] = ELFMAG3;
- ehdr.e_ident[4] = ELFCLASSW;
- ehdr.e_ident[5] = ELFDATA2LSB;
- ehdr.e_ident[6] = EV_CURRENT;
- #if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
- /* FIXME: should set only for freebsd _target_, but we exclude only PE target */
- ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
- #endif
- #ifdef TCC_TARGET_ARM
- #ifdef TCC_ARM_EABI
- ehdr.e_ident[EI_OSABI] = 0;
- ehdr.e_flags = EF_ARM_EABI_VER4;
- if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL)
- ehdr.e_flags |= EF_ARM_HASENTRY;
- if (s1->float_abi == ARM_HARD_FLOAT)
- ehdr.e_flags |= EF_ARM_VFP_FLOAT;
- else
- ehdr.e_flags |= EF_ARM_SOFT_FLOAT;
- #else
- ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
- #endif
- #endif
- switch(file_type) {
- default:
- case TCC_OUTPUT_EXE:
- ehdr.e_type = ET_EXEC;
- ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1);
- break;
- case TCC_OUTPUT_DLL:
- ehdr.e_type = ET_DYN;
- ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
- break;
- case TCC_OUTPUT_OBJ:
- ehdr.e_type = ET_REL;
- break;
- }
- ehdr.e_machine = EM_TCC_TARGET;
- ehdr.e_version = EV_CURRENT;
- ehdr.e_shoff = file_offset;
- ehdr.e_ehsize = sizeof(ElfW(Ehdr));
- ehdr.e_shentsize = sizeof(ElfW(Shdr));
- ehdr.e_shnum = shnum;
- ehdr.e_shstrndx = shnum - 1;
- fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f);
- fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f);
- offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
- sort_syms(s1, symtab_section);
- for(i = 1; i < s1->nb_sections; i++) {
- s = s1->sections[sec_order[i]];
- if (s->sh_type != SHT_NOBITS) {
- while (offset < s->sh_offset) {
- fputc(0, f);
- offset++;
- }
- size = s->sh_size;
- if (size)
- fwrite(s->data, 1, size, f);
- offset += size;
- }
- }
- /* output section headers */
- while (offset < ehdr.e_shoff) {
- fputc(0, f);
- offset++;
- }
- for(i = 0; i < s1->nb_sections; i++) {
- sh = &shdr;
- memset(sh, 0, sizeof(ElfW(Shdr)));
- s = s1->sections[i];
- if (s) {
- sh->sh_name = s->sh_name;
- sh->sh_type = s->sh_type;
- sh->sh_flags = s->sh_flags;
- sh->sh_entsize = s->sh_entsize;
- sh->sh_info = s->sh_info;
- if (s->link)
- sh->sh_link = s->link->sh_num;
- sh->sh_addralign = s->sh_addralign;
- sh->sh_addr = s->sh_addr;
- sh->sh_offset = s->sh_offset;
- sh->sh_size = s->sh_size;
- }
- fwrite(sh, 1, sizeof(ElfW(Shdr)), f);
- }
- }
- /* Write an elf, coff or "binary" file */
- static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum,
- ElfW(Phdr) *phdr, int file_offset, int *sec_order)
- {
- int fd, mode, file_type;
- FILE *f;
- file_type = s1->output_type;
- if (file_type == TCC_OUTPUT_OBJ)
- mode = 0666;
- else
- mode = 0777;
- unlink(filename);
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
- if (fd < 0) {
- tcc_error_noabort("could not write '%s'", filename);
- return -1;
- }
- f = fdopen(fd, "wb");
- if (s1->verbose)
- printf("<- %s\n", filename);
- #ifdef TCC_TARGET_COFF
- if (s1->output_format == TCC_OUTPUT_FORMAT_COFF)
- tcc_output_coff(s1, f);
- else
- #endif
- if (s1->output_format == TCC_OUTPUT_FORMAT_ELF)
- tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order);
- else
- tcc_output_binary(s1, f, sec_order);
- fclose(f);
- return 0;
- }
- /* Sort section headers by assigned sh_addr, remove sections
- that we aren't going to output. */
- static void tidy_section_headers(TCCState *s1, int *sec_order)
- {
- int i, nnew, l, *backmap;
- Section **snew, *s;
- ElfW(Sym) *sym;
- snew = tcc_malloc(s1->nb_sections * sizeof(snew[0]));
- backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0]));
- for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) {
- s = s1->sections[sec_order[i]];
- if (!i || s->sh_name) {
- backmap[sec_order[i]] = nnew;
- snew[nnew] = s;
- ++nnew;
- } else {
- backmap[sec_order[i]] = 0;
- snew[--l] = s;
- }
- }
- for (i = 0; i < nnew; i++) {
- s = snew[i];
- if (s) {
- s->sh_num = i;
- if (s->sh_type == SHT_RELX)
- s->sh_info = backmap[s->sh_info];
- }
- }
- for_each_elem(symtab_section, 1, sym, ElfW(Sym))
- if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
- sym->st_shndx = backmap[sym->st_shndx];
- if( !s1->static_link ) {
- for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
- if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
- sym->st_shndx = backmap[sym->st_shndx];
- }
- for (i = 0; i < s1->nb_sections; i++)
- sec_order[i] = i;
- tcc_free(s1->sections);
- s1->sections = snew;
- s1->nb_sections = nnew;
- tcc_free(backmap);
- }
- /* Output an elf, coff or binary file */
- /* XXX: suppress unneeded sections */
- static int elf_output_file(TCCState *s1, const char *filename)
- {
- int i, ret, phnum, shnum, file_type, file_offset, *sec_order;
- struct dyn_inf dyninf = {0};
- ElfW(Phdr) *phdr;
- ElfW(Sym) *sym;
- Section *strsec, *interp, *dynamic, *dynstr;
- int textrel;
- file_type = s1->output_type;
- s1->nb_errors = 0;
- ret = -1;
- phdr = NULL;
- sec_order = NULL;
- interp = dynamic = dynstr = NULL; /* avoid warning */
- textrel = 0;
- if (file_type != TCC_OUTPUT_OBJ) {
- /* if linking, also link in runtime libraries (libc, libgcc, etc.) */
- tcc_add_runtime(s1);
- relocate_common_syms();
- tcc_add_linker_symbols(s1);
- if (!s1->static_link) {
- if (file_type == TCC_OUTPUT_EXE) {
- char *ptr;
- /* allow override the dynamic loader */
- const char *elfint = getenv("LD_SO");
- if (elfint == NULL)
- elfint = DEFAULT_ELFINTERP(s1);
- /* add interpreter section only if executable */
- interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
- interp->sh_addralign = 1;
- ptr = section_ptr_add(interp, 1 + strlen(elfint));
- strcpy(ptr, elfint);
- }
- /* add dynamic symbol table */
- s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC,
- ".dynstr",
- ".hash", SHF_ALLOC);
- dynstr = s1->dynsym->link;
- /* add dynamic section */
- dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
- SHF_ALLOC | SHF_WRITE);
- dynamic->link = dynstr;
- dynamic->sh_entsize = sizeof(ElfW(Dyn));
- build_got(s1);
- if (file_type == TCC_OUTPUT_EXE) {
- bind_exe_dynsyms(s1);
- if (s1->nb_errors)
- goto the_end;
- bind_libs_dynsyms(s1);
- } else {
- /* shared library case: simply export all global symbols */
- export_global_syms(s1);
- }
- }
- build_got_entries(s1);
- }
- /* we add a section for symbols */
- strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
- put_elf_str(strsec, "");
- /* Allocate strings for section names */
- textrel = alloc_sec_names(s1, file_type, strsec);
- if (dynamic) {
- /* add a list of needed dlls */
- for(i = 0; i < s1->nb_loaded_dlls; i++) {
- DLLReference *dllref = s1->loaded_dlls[i];
- if (dllref->level == 0)
- put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
- }
- if (s1->rpath)
- put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
- put_elf_str(dynstr, s1->rpath));
- if (file_type == TCC_OUTPUT_DLL) {
- if (s1->soname)
- put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
- /* XXX: currently, since we do not handle PIC code, we
- must relocate the readonly segments */
- if (textrel)
- put_dt(dynamic, DT_TEXTREL, 0);
- }
- if (s1->symbolic)
- put_dt(dynamic, DT_SYMBOLIC, 0);
- dyninf.dynamic = dynamic;
- dyninf.dynstr = dynstr;
- /* remember offset and reserve space for 2nd call below */
- dyninf.data_offset = dynamic->data_offset;
- fill_dynamic(s1, &dyninf);
- dynamic->sh_size = dynamic->data_offset;
- dynstr->sh_size = dynstr->data_offset;
- }
- /* compute number of program headers */
- if (file_type == TCC_OUTPUT_OBJ)
- phnum = 0;
- else if (file_type == TCC_OUTPUT_DLL)
- phnum = 3;
- else if (s1->static_link)
- phnum = 2;
- else
- phnum = 5;
- /* allocate program segment headers */
- phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
- /* compute number of sections */
- shnum = s1->nb_sections;
- /* this array is used to reorder sections in the output file */
- sec_order = tcc_malloc(sizeof(int) * shnum);
- sec_order[0] = 0;
- /* compute section to program header mapping */
- file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf,
- sec_order);
- /* Fill remaining program header and finalize relocation related to dynamic
- linking. */
- if (file_type != TCC_OUTPUT_OBJ) {
- fill_unloadable_phdr(phdr, phnum, interp, dynamic);
- if (dynamic) {
- dynamic->data_offset = dyninf.data_offset;
- fill_dynamic(s1, &dyninf);
- /* put in GOT the dynamic section address and relocate PLT */
- write32le(s1->got->data, dynamic->sh_addr);
- if (file_type == TCC_OUTPUT_EXE
- || (RELOCATE_DLLPLT && file_type == TCC_OUTPUT_DLL))
- relocate_plt(s1);
- /* relocate symbols in .dynsym now that final addresses are known */
- for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) {
- if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) {
- /* do symbol relocation */
- sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
- }
- }
- }
- /* if building executable or DLL, then relocate each section
- except the GOT which is already relocated */
- ret = final_sections_reloc(s1);
- if (ret)
- goto the_end;
- tidy_section_headers(s1, sec_order);
- /* Perform relocation to GOT or PLT entries */
- if (file_type == TCC_OUTPUT_EXE && s1->static_link)
- fill_got(s1);
- else if (s1->got)
- fill_local_got_entries(s1);
- }
- /* Create the ELF file with name 'filename' */
- ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
- s1->nb_sections = shnum;
- the_end:
- tcc_free(sec_order);
- tcc_free(phdr);
- return ret;
- }
- LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename)
- {
- int ret;
- #ifdef TCC_TARGET_PE
- if (s->output_type != TCC_OUTPUT_OBJ) {
- ret = pe_output_file(s, filename);
- } else
- #endif
- ret = elf_output_file(s, filename);
- return ret;
- }
- static void *load_data(int fd, unsigned long file_offset, unsigned long size)
- {
- void *data;
- data = tcc_malloc(size);
- lseek(fd, file_offset, SEEK_SET);
- read(fd, data, size);
- return data;
- }
- typedef struct SectionMergeInfo {
- Section *s; /* corresponding existing section */
- unsigned long offset; /* offset of the new section in the existing section */
- uint8_t new_section; /* true if section 's' was added */
- uint8_t link_once; /* true if link once section */
- } SectionMergeInfo;
- ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h)
- {
- int size = read(fd, h, sizeof *h);
- if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) {
- if (h->e_type == ET_REL)
- return AFF_BINTYPE_REL;
- if (h->e_type == ET_DYN)
- return AFF_BINTYPE_DYN;
- } else if (size >= 8) {
- if (0 == memcmp(h, ARMAG, 8))
- return AFF_BINTYPE_AR;
- #ifdef TCC_TARGET_COFF
- if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC)
- return AFF_BINTYPE_C67;
- #endif
- }
- return 0;
- }
- /* load an object file and merge it with current files */
- /* XXX: handle correctly stab (debug) info */
- ST_FUNC int tcc_load_object_file(TCCState *s1,
- int fd, unsigned long file_offset)
- {
- ElfW(Ehdr) ehdr;
- ElfW(Shdr) *shdr, *sh;
- int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed;
- unsigned char *strsec, *strtab;
- int *old_to_new_syms;
- char *sh_name, *name;
- SectionMergeInfo *sm_table, *sm;
- ElfW(Sym) *sym, *symtab;
- ElfW_Rel *rel;
- Section *s;
- int stab_index;
- int stabstr_index;
- stab_index = stabstr_index = 0;
- lseek(fd, file_offset, SEEK_SET);
- if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL)
- goto fail1;
- /* test CPU specific stuff */
- if (ehdr.e_ident[5] != ELFDATA2LSB ||
- ehdr.e_machine != EM_TCC_TARGET) {
- fail1:
- tcc_error_noabort("invalid object file");
- return -1;
- }
- /* read sections */
- shdr = load_data(fd, file_offset + ehdr.e_shoff,
- sizeof(ElfW(Shdr)) * ehdr.e_shnum);
- sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum);
- /* load section names */
- sh = &shdr[ehdr.e_shstrndx];
- strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
- /* load symtab and strtab */
- old_to_new_syms = NULL;
- symtab = NULL;
- strtab = NULL;
- nb_syms = 0;
- seencompressed = 0;
- for(i = 1; i < ehdr.e_shnum; i++) {
- sh = &shdr[i];
- if (sh->sh_type == SHT_SYMTAB) {
- if (symtab) {
- tcc_error_noabort("object must contain only one symtab");
- fail:
- ret = -1;
- goto the_end;
- }
- nb_syms = sh->sh_size / sizeof(ElfW(Sym));
- symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
- sm_table[i].s = symtab_section;
- /* now load strtab */
- sh = &shdr[sh->sh_link];
- strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
- }
- if (sh->sh_flags & SHF_COMPRESSED)
- seencompressed = 1;
- }
- /* now examine each section and try to merge its content with the
- ones in memory */
- for(i = 1; i < ehdr.e_shnum; i++) {
- /* no need to examine section name strtab */
- if (i == ehdr.e_shstrndx)
- continue;
- sh = &shdr[i];
- sh_name = (char *) strsec + sh->sh_name;
- /* ignore sections types we do not handle */
- if (sh->sh_type != SHT_PROGBITS &&
- sh->sh_type != SHT_RELX &&
- #ifdef TCC_ARM_EABI
- sh->sh_type != SHT_ARM_EXIDX &&
- #endif
- sh->sh_type != SHT_NOBITS &&
- sh->sh_type != SHT_PREINIT_ARRAY &&
- sh->sh_type != SHT_INIT_ARRAY &&
- sh->sh_type != SHT_FINI_ARRAY &&
- strcmp(sh_name, ".stabstr")
- )
- continue;
- if (seencompressed
- && (!strncmp(sh_name, ".debug_", sizeof(".debug_")-1)
- || (sh->sh_type == SHT_RELX
- && !strncmp((char*)strsec + shdr[sh->sh_info].sh_name,
- ".debug_", sizeof(".debug_")-1))))
- continue;
- if (sh->sh_addralign < 1)
- sh->sh_addralign = 1;
- /* find corresponding section, if any */
- for(j = 1; j < s1->nb_sections;j++) {
- s = s1->sections[j];
- if (!strcmp(s->name, sh_name)) {
- if (!strncmp(sh_name, ".gnu.linkonce",
- sizeof(".gnu.linkonce") - 1)) {
- /* if a 'linkonce' section is already present, we
- do not add it again. It is a little tricky as
- symbols can still be defined in
- it. */
- sm_table[i].link_once = 1;
- goto next;
- } else {
- goto found;
- }
- }
- }
- /* not found: create new section */
- s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags & ~SHF_GROUP);
- /* take as much info as possible from the section. sh_link and
- sh_info will be updated later */
- s->sh_addralign = sh->sh_addralign;
- s->sh_entsize = sh->sh_entsize;
- sm_table[i].new_section = 1;
- found:
- if (sh->sh_type != s->sh_type) {
- tcc_error_noabort("invalid section type");
- goto fail;
- }
- /* align start of section */
- offset = s->data_offset;
- if (0 == strcmp(sh_name, ".stab")) {
- stab_index = i;
- goto no_align;
- }
- if (0 == strcmp(sh_name, ".stabstr")) {
- stabstr_index = i;
- goto no_align;
- }
- size = sh->sh_addralign - 1;
- offset = (offset + size) & ~size;
- if (sh->sh_addralign > s->sh_addralign)
- s->sh_addralign = sh->sh_addralign;
- s->data_offset = offset;
- no_align:
- sm_table[i].offset = offset;
- sm_table[i].s = s;
- /* concatenate sections */
- size = sh->sh_size;
- if (sh->sh_type != SHT_NOBITS) {
- unsigned char *ptr;
- lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
- ptr = section_ptr_add(s, size);
- read(fd, ptr, size);
- } else {
- s->data_offset += size;
- }
- next: ;
- }
- /* gr relocate stab strings */
- if (stab_index && stabstr_index) {
- Stab_Sym *a, *b;
- unsigned o;
- s = sm_table[stab_index].s;
- a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
- b = (Stab_Sym *)(s->data + s->data_offset);
- o = sm_table[stabstr_index].offset;
- while (a < b)
- a->n_strx += o, a++;
- }
- /* second short pass to update sh_link and sh_info fields of new
- sections */
- for(i = 1; i < ehdr.e_shnum; i++) {
- s = sm_table[i].s;
- if (!s || !sm_table[i].new_section)
- continue;
- sh = &shdr[i];
- if (sh->sh_link > 0)
- s->link = sm_table[sh->sh_link].s;
- if (sh->sh_type == SHT_RELX) {
- s->sh_info = sm_table[sh->sh_info].s->sh_num;
- /* update backward link */
- s1->sections[s->sh_info]->reloc = s;
- }
- }
- sm = sm_table;
- /* resolve symbols */
- old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
- sym = symtab + 1;
- for(i = 1; i < nb_syms; i++, sym++) {
- if (sym->st_shndx != SHN_UNDEF &&
- sym->st_shndx < SHN_LORESERVE) {
- sm = &sm_table[sym->st_shndx];
- if (sm->link_once) {
- /* if a symbol is in a link once section, we use the
- already defined symbol. It is very important to get
- correct relocations */
- if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
- name = (char *) strtab + sym->st_name;
- sym_index = find_elf_sym(symtab_section, name);
- if (sym_index)
- old_to_new_syms[i] = sym_index;
- }
- continue;
- }
- /* if no corresponding section added, no need to add symbol */
- if (!sm->s)
- continue;
- /* convert section number */
- sym->st_shndx = sm->s->sh_num;
- /* offset value */
- sym->st_value += sm->offset;
- }
- /* add symbol */
- name = (char *) strtab + sym->st_name;
- sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size,
- sym->st_info, sym->st_other,
- sym->st_shndx, name);
- old_to_new_syms[i] = sym_index;
- }
- /* third pass to patch relocation entries */
- for(i = 1; i < ehdr.e_shnum; i++) {
- s = sm_table[i].s;
- if (!s)
- continue;
- sh = &shdr[i];
- offset = sm_table[i].offset;
- switch(s->sh_type) {
- case SHT_RELX:
- /* take relocation offset information */
- offseti = sm_table[sh->sh_info].offset;
- for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) {
- int type;
- unsigned sym_index;
- /* convert symbol index */
- type = ELFW(R_TYPE)(rel->r_info);
- sym_index = ELFW(R_SYM)(rel->r_info);
- /* NOTE: only one symtab assumed */
- if (sym_index >= nb_syms)
- goto invalid_reloc;
- sym_index = old_to_new_syms[sym_index];
- /* ignore link_once in rel section. */
- if (!sym_index && !sm->link_once
- #ifdef TCC_TARGET_ARM
- && type != R_ARM_V4BX
- #endif
- ) {
- invalid_reloc:
- tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x",
- i, strsec + sh->sh_name, rel->r_offset);
- goto fail;
- }
- rel->r_info = ELFW(R_INFO)(sym_index, type);
- /* offset the relocation offset */
- rel->r_offset += offseti;
- #ifdef TCC_TARGET_ARM
- /* Jumps and branches from a Thumb code to a PLT entry need
- special handling since PLT entries are ARM code.
- Unconditional bl instructions referencing PLT entries are
- handled by converting these instructions into blx
- instructions. Other case of instructions referencing a PLT
- entry require to add a Thumb stub before the PLT entry to
- switch to ARM mode. We set bit plt_thumb_stub of the
- attribute of a symbol to indicate such a case. */
- if (type == R_ARM_THM_JUMP24)
- get_sym_attr(s1, sym_index, 1)->plt_thumb_stub = 1;
- #endif
- }
- break;
- default:
- break;
- }
- }
- ret = 0;
- the_end:
- tcc_free(symtab);
- tcc_free(strtab);
- tcc_free(old_to_new_syms);
- tcc_free(sm_table);
- tcc_free(strsec);
- tcc_free(shdr);
- return ret;
- }
- typedef struct ArchiveHeader {
- char ar_name[16]; /* name of this member */
- char ar_date[12]; /* file mtime */
- char ar_uid[6]; /* owner uid; printed as decimal */
- char ar_gid[6]; /* owner gid; printed as decimal */
- char ar_mode[8]; /* file mode, printed as octal */
- char ar_size[10]; /* file size, printed as decimal */
- char ar_fmag[2]; /* should contain ARFMAG */
- } ArchiveHeader;
- static int get_be32(const uint8_t *b)
- {
- return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24);
- }
- static long get_be64(const uint8_t *b)
- {
- long long ret = get_be32(b);
- ret = (ret << 32) | (unsigned)get_be32(b+4);
- return (long)ret;
- }
- /* load only the objects which resolve undefined symbols */
- static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
- {
- long i, bound, nsyms, sym_index, off, ret;
- uint8_t *data;
- const char *ar_names, *p;
- const uint8_t *ar_index;
- ElfW(Sym) *sym;
- data = tcc_malloc(size);
- if (read(fd, data, size) != size)
- goto fail;
- nsyms = entrysize == 4 ? get_be32(data) : get_be64(data);
- ar_index = data + entrysize;
- ar_names = (char *) ar_index + nsyms * entrysize;
- do {
- bound = 0;
- for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
- sym_index = find_elf_sym(symtab_section, p);
- if(sym_index) {
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
- if(sym->st_shndx == SHN_UNDEF) {
- off = (entrysize == 4
- ? get_be32(ar_index + i * 4)
- : get_be64(ar_index + i * 8))
- + sizeof(ArchiveHeader);
- ++bound;
- if(tcc_load_object_file(s1, fd, off) < 0) {
- fail:
- ret = -1;
- goto the_end;
- }
- }
- }
- }
- } while(bound);
- ret = 0;
- the_end:
- tcc_free(data);
- return ret;
- }
- /* load a '.a' file */
- ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
- {
- ArchiveHeader hdr;
- char ar_size[11];
- char ar_name[17];
- char magic[8];
- int size, len, i;
- unsigned long file_offset;
- /* skip magic which was already checked */
- read(fd, magic, sizeof(magic));
- for(;;) {
- len = read(fd, &hdr, sizeof(hdr));
- if (len == 0)
- break;
- if (len != sizeof(hdr)) {
- tcc_error_noabort("invalid archive");
- return -1;
- }
- memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size));
- ar_size[sizeof(hdr.ar_size)] = '\0';
- size = strtol(ar_size, NULL, 0);
- memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name));
- for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) {
- if (ar_name[i] != ' ')
- break;
- }
- ar_name[i + 1] = '\0';
- file_offset = lseek(fd, 0, SEEK_CUR);
- /* align to even */
- size = (size + 1) & ~1;
- if (!strcmp(ar_name, "/")) {
- /* coff symbol table : we handle it */
- if(s1->alacarte_link)
- return tcc_load_alacarte(s1, fd, size, 4);
- } else if (!strcmp(ar_name, "/SYM64/")) {
- if(s1->alacarte_link)
- return tcc_load_alacarte(s1, fd, size, 8);
- } else {
- ElfW(Ehdr) ehdr;
- if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
- if (tcc_load_object_file(s1, fd, file_offset) < 0)
- return -1;
- }
- }
- lseek(fd, file_offset + size, SEEK_SET);
- }
- return 0;
- }
- #ifndef TCC_TARGET_PE
- /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
- is referenced by the user (so it should be added as DT_NEEDED in
- the generated ELF file) */
- ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
- {
- ElfW(Ehdr) ehdr;
- ElfW(Shdr) *shdr, *sh, *sh1;
- int i, j, nb_syms, nb_dts, sym_bind, ret;
- ElfW(Sym) *sym, *dynsym;
- ElfW(Dyn) *dt, *dynamic;
- unsigned char *dynstr;
- const char *name, *soname;
- DLLReference *dllref;
- read(fd, &ehdr, sizeof(ehdr));
- /* test CPU specific stuff */
- if (ehdr.e_ident[5] != ELFDATA2LSB ||
- ehdr.e_machine != EM_TCC_TARGET) {
- tcc_error_noabort("bad architecture");
- return -1;
- }
- /* read sections */
- shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum);
- /* load dynamic section and dynamic symbols */
- nb_syms = 0;
- nb_dts = 0;
- dynamic = NULL;
- dynsym = NULL; /* avoid warning */
- dynstr = NULL; /* avoid warning */
- for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
- switch(sh->sh_type) {
- case SHT_DYNAMIC:
- nb_dts = sh->sh_size / sizeof(ElfW(Dyn));
- dynamic = load_data(fd, sh->sh_offset, sh->sh_size);
- break;
- case SHT_DYNSYM:
- nb_syms = sh->sh_size / sizeof(ElfW(Sym));
- dynsym = load_data(fd, sh->sh_offset, sh->sh_size);
- sh1 = &shdr[sh->sh_link];
- dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
- break;
- default:
- break;
- }
- }
- /* compute the real library name */
- soname = tcc_basename(filename);
- for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
- if (dt->d_tag == DT_SONAME) {
- soname = (char *) dynstr + dt->d_un.d_val;
- }
- }
- /* if the dll is already loaded, do not load it */
- for(i = 0; i < s1->nb_loaded_dlls; i++) {
- dllref = s1->loaded_dlls[i];
- if (!strcmp(soname, dllref->name)) {
- /* but update level if needed */
- if (level < dllref->level)
- dllref->level = level;
- ret = 0;
- goto the_end;
- }
- }
- /* add the dll and its level */
- dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
- dllref->level = level;
- strcpy(dllref->name, soname);
- dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
- /* add dynamic symbols in dynsym_section */
- for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
- sym_bind = ELFW(ST_BIND)(sym->st_info);
- if (sym_bind == STB_LOCAL)
- continue;
- name = (char *) dynstr + sym->st_name;
- set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
- sym->st_info, sym->st_other, sym->st_shndx, name);
- }
- /* load all referenced DLLs */
- for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
- switch(dt->d_tag) {
- case DT_NEEDED:
- name = (char *) dynstr + dt->d_un.d_val;
- for(j = 0; j < s1->nb_loaded_dlls; j++) {
- dllref = s1->loaded_dlls[j];
- if (!strcmp(name, dllref->name))
- goto already_loaded;
- }
- if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) {
- tcc_error_noabort("referenced dll '%s' not found", name);
- ret = -1;
- goto the_end;
- }
- already_loaded:
- break;
- }
- }
- ret = 0;
- the_end:
- tcc_free(dynstr);
- tcc_free(dynsym);
- tcc_free(dynamic);
- tcc_free(shdr);
- return ret;
- }
- #define LD_TOK_NAME 256
- #define LD_TOK_EOF (-1)
- /* return next ld script token */
- static int ld_next(TCCState *s1, char *name, int name_size)
- {
- int c;
- char *q;
- redo:
- switch(ch) {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- case '\r':
- case '\n':
- inp();
- goto redo;
- case '/':
- minp();
- if (ch == '*') {
- file->buf_ptr = parse_comment(file->buf_ptr);
- ch = file->buf_ptr[0];
- goto redo;
- } else {
- q = name;
- *q++ = '/';
- goto parse_name;
- }
- break;
- case '\\':
- ch = handle_eob();
- if (ch != '\\')
- goto redo;
- /* fall through */
- /* case 'a' ... 'z': */
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'i':
- case 'j':
- case 'k':
- case 'l':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v':
- case 'w':
- case 'x':
- case 'y':
- case 'z':
- /* case 'A' ... 'z': */
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- case 'G':
- case 'H':
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- case 'Q':
- case 'R':
- case 'S':
- case 'T':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'Z':
- case '_':
- case '.':
- case '$':
- case '~':
- q = name;
- parse_name:
- for(;;) {
- if (!((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch >= '0' && ch <= '9') ||
- strchr("/.-_+=$:\\,~", ch)))
- break;
- if ((q - name) < name_size - 1) {
- *q++ = ch;
- }
- minp();
- }
- *q = '\0';
- c = LD_TOK_NAME;
- break;
- case CH_EOF:
- c = LD_TOK_EOF;
- break;
- default:
- c = ch;
- inp();
- break;
- }
- return c;
- }
- static int ld_add_file(TCCState *s1, const char filename[])
- {
- if (filename[0] == '/') {
- if (CONFIG_SYSROOT[0] == '\0'
- && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0)
- return 0;
- filename = tcc_basename(filename);
- }
- return tcc_add_dll(s1, filename, 0);
- }
- static inline int new_undef_syms(void)
- {
- int ret = 0;
- ret = new_undef_sym;
- new_undef_sym = 0;
- return ret;
- }
- static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
- {
- char filename[1024], libname[1024];
- int t, group, nblibs = 0, ret = 0;
- char **libs = NULL;
- group = !strcmp(cmd, "GROUP");
- if (!as_needed)
- new_undef_syms();
- t = ld_next(s1, filename, sizeof(filename));
- if (t != '(')
- expect("(");
- t = ld_next(s1, filename, sizeof(filename));
- for(;;) {
- libname[0] = '\0';
- if (t == LD_TOK_EOF) {
- tcc_error_noabort("unexpected end of file");
- ret = -1;
- goto lib_parse_error;
- } else if (t == ')') {
- break;
- } else if (t == '-') {
- t = ld_next(s1, filename, sizeof(filename));
- if ((t != LD_TOK_NAME) || (filename[0] != 'l')) {
- tcc_error_noabort("library name expected");
- ret = -1;
- goto lib_parse_error;
- }
- pstrcpy(libname, sizeof libname, &filename[1]);
- if (s1->static_link) {
- snprintf(filename, sizeof filename, "lib%s.a", libname);
- } else {
- snprintf(filename, sizeof filename, "lib%s.so", libname);
- }
- } else if (t != LD_TOK_NAME) {
- tcc_error_noabort("filename expected");
- ret = -1;
- goto lib_parse_error;
- }
- if (!strcmp(filename, "AS_NEEDED")) {
- ret = ld_add_file_list(s1, cmd, 1);
- if (ret)
- goto lib_parse_error;
- } else {
- /* TODO: Implement AS_NEEDED support. Ignore it for now */
- if (!as_needed) {
- ret = ld_add_file(s1, filename);
- if (ret)
- goto lib_parse_error;
- if (group) {
- /* Add the filename *and* the libname to avoid future conversions */
- dynarray_add(&libs, &nblibs, tcc_strdup(filename));
- if (libname[0] != '\0')
- dynarray_add(&libs, &nblibs, tcc_strdup(libname));
- }
- }
- }
- t = ld_next(s1, filename, sizeof(filename));
- if (t == ',') {
- t = ld_next(s1, filename, sizeof(filename));
- }
- }
- if (group && !as_needed) {
- while (new_undef_syms()) {
- int i;
- for (i = 0; i < nblibs; i ++)
- ld_add_file(s1, libs[i]);
- }
- }
- lib_parse_error:
- dynarray_reset(&libs, &nblibs);
- return ret;
- }
- /* interpret a subset of GNU ldscripts to handle the dummy libc.so
- files */
- ST_FUNC int tcc_load_ldscript(TCCState *s1)
- {
- char cmd[64];
- char filename[1024];
- int t, ret;
- ch = handle_eob();
- for(;;) {
- t = ld_next(s1, cmd, sizeof(cmd));
- if (t == LD_TOK_EOF)
- return 0;
- else if (t != LD_TOK_NAME)
- return -1;
- if (!strcmp(cmd, "INPUT") ||
- !strcmp(cmd, "GROUP")) {
- ret = ld_add_file_list(s1, cmd, 0);
- if (ret)
- return ret;
- } else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
- !strcmp(cmd, "TARGET")) {
- /* ignore some commands */
- t = ld_next(s1, cmd, sizeof(cmd));
- if (t != '(')
- expect("(");
- for(;;) {
- t = ld_next(s1, filename, sizeof(filename));
- if (t == LD_TOK_EOF) {
- tcc_error_noabort("unexpected end of file");
- return -1;
- } else if (t == ')') {
- break;
- }
- }
- } else {
- return -1;
- }
- }
- return 0;
- }
- #endif /* !TCC_TARGET_PE */
|