| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488 |
- /* ----------------------------------------------------------------------- *
- *
- * Copyright 1996-2018 The NASM Authors - All Rights Reserved
- * See the file AUTHORS included with the NASM distribution for
- * the specific copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following
- * conditions are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ----------------------------------------------------------------------- */
- /*
- * outmacho.c output routines for the Netwide Assembler to produce
- * NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files
- */
- #include "compiler.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include "nasm.h"
- #include "nasmlib.h"
- #include "ilog2.h"
- #include "labels.h"
- #include "error.h"
- #include "saa.h"
- #include "raa.h"
- #include "rbtree.h"
- #include "hashtbl.h"
- #include "outform.h"
- #include "outlib.h"
- #include "ver.h"
- #include "dwarf.h"
- #if defined(OF_MACHO) || defined(OF_MACHO64)
- /* Mach-O in-file header structure sizes */
- #define MACHO_HEADER_SIZE 28
- #define MACHO_SEGCMD_SIZE 56
- #define MACHO_SECTCMD_SIZE 68
- #define MACHO_SYMCMD_SIZE 24
- #define MACHO_NLIST_SIZE 12
- #define MACHO_RELINFO_SIZE 8
- #define MACHO_HEADER64_SIZE 32
- #define MACHO_SEGCMD64_SIZE 72
- #define MACHO_SECTCMD64_SIZE 80
- #define MACHO_NLIST64_SIZE 16
- /* Mach-O file header values */
- #define MH_MAGIC 0xfeedface
- #define MH_MAGIC_64 0xfeedfacf
- #define CPU_TYPE_I386 7 /* x86 platform */
- #define CPU_TYPE_X86_64 0x01000007 /* x86-64 platform */
- #define CPU_SUBTYPE_I386_ALL 3 /* all-x86 compatible */
- #define MH_OBJECT 0x1 /* object file */
- /* Mach-O header flags */
- #define MH_SUBSECTIONS_VIA_SYMBOLS 0x2000
- /* Mach-O load commands */
- #define LC_SEGMENT 0x1 /* 32-bit segment load cmd */
- #define LC_SEGMENT_64 0x19 /* 64-bit segment load cmd */
- #define LC_SYMTAB 0x2 /* symbol table load command */
- /* Mach-O relocations numbers */
- /* Generic relocs, used by i386 Mach-O */
- #define GENERIC_RELOC_VANILLA 0 /* Generic relocation */
- #define GENERIC_RELOC_TLV 5 /* Thread local */
- #define X86_64_RELOC_UNSIGNED 0 /* Absolute address */
- #define X86_64_RELOC_SIGNED 1 /* Signed 32-bit disp */
- #define X86_64_RELOC_BRANCH 2 /* CALL/JMP with 32-bit disp */
- #define X86_64_RELOC_GOT_LOAD 3 /* MOVQ of GOT entry */
- #define X86_64_RELOC_GOT 4 /* Different GOT entry */
- #define X86_64_RELOC_SUBTRACTOR 5 /* Subtracting two symbols */
- #define X86_64_RELOC_SIGNED_1 6 /* SIGNED with -1 addend */
- #define X86_64_RELOC_SIGNED_2 7 /* SIGNED with -2 addend */
- #define X86_64_RELOC_SIGNED_4 8 /* SIGNED with -4 addend */
- #define X86_64_RELOC_TLV 9 /* Thread local */
- /* Mach-O VM permission constants */
- #define VM_PROT_NONE (0x00)
- #define VM_PROT_READ (0x01)
- #define VM_PROT_WRITE (0x02)
- #define VM_PROT_EXECUTE (0x04)
- #define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
- #define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
- /* Our internal relocation types */
- enum reltype {
- RL_ABS, /* Absolute relocation */
- RL_REL, /* Relative relocation */
- RL_TLV, /* Thread local */
- RL_BRANCH, /* Relative direct branch */
- RL_SUB, /* X86_64_RELOC_SUBTRACT */
- RL_GOT, /* X86_64_RELOC_GOT */
- RL_GOTLOAD /* X86_64_RELOC_GOT_LOAD */
- };
- #define RL_MAX_32 RL_TLV
- #define RL_MAX_64 RL_GOTLOAD
- struct macho_fmt {
- uint32_t ptrsize; /* Pointer size in bytes */
- uint32_t mh_magic; /* Which magic number to use */
- uint32_t cpu_type; /* Which CPU type */
- uint32_t lc_segment; /* Which segment load command */
- uint32_t header_size; /* Header size */
- uint32_t segcmd_size; /* Segment command size */
- uint32_t sectcmd_size; /* Section command size */
- uint32_t nlist_size; /* Nlist (symbol) size */
- enum reltype maxreltype; /* Maximum entry in enum reltype permitted */
- uint32_t reloc_abs; /* Absolute relocation type */
- uint32_t reloc_rel; /* Relative relocation type */
- uint32_t reloc_tlv; /* Thread local relocation type */
- bool forcesym; /* Always use "external" (symbol-relative) relocations */
- };
- static struct macho_fmt fmt;
- static void fwriteptr(uint64_t data, FILE * fp)
- {
- fwriteaddr(data, fmt.ptrsize, fp);
- }
- struct section {
- /* nasm internal data */
- struct section *next;
- struct SAA *data;
- int32_t index; /* Main section index */
- int32_t subsection; /* Current subsection index */
- int32_t fileindex;
- struct reloc *relocs;
- struct rbtree *syms[2]; /* All/global symbols symbols in section */
- int align;
- bool by_name; /* This section was specified by full MachO name */
- char namestr[34]; /* segment,section as a C string */
- /* data that goes into the file */
- char sectname[16]; /* what this section is called */
- char segname[16]; /* segment this section will be in */
- uint64_t addr; /* in-memory address (subject to alignment) */
- uint64_t size; /* in-memory and -file size */
- uint64_t offset; /* in-file offset */
- uint32_t pad; /* padding bytes before section */
- uint32_t nreloc; /* relocation entry count */
- uint32_t flags; /* type and attributes (masked) */
- uint32_t extreloc; /* external relocations */
- };
- #define SECTION_TYPE 0x000000ff /* section type mask */
- #define S_REGULAR (0x0) /* standard section */
- #define S_ZEROFILL (0x1) /* zerofill, in-memory only */
- #define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */
- #define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some
- machine instructions */
- #define S_ATTR_EXT_RELOC 0x00000200 /* section has external relocation entries */
- #define S_ATTR_LOC_RELOC 0x00000100 /* section has local relocation entries */
- #define S_ATTR_DEBUG 0x02000000
- #define S_ATTR_SELF_MODIFYING_CODE 0x04000000
- #define S_ATTR_LIVE_SUPPORT 0x08000000
- #define S_ATTR_NO_DEAD_STRIP 0x10000000 /* no dead stripping */
- #define S_ATTR_STRIP_STATIC_SYMS 0x20000000
- #define S_ATTR_NO_TOC 0x40000000
- #define S_ATTR_PURE_INSTRUCTIONS 0x80000000 /* section uses pure machine instructions */
- #define S_ATTR_DEBUG 0x02000000 /* debug section */
- #define S_NASM_TYPE_MASK 0x800004ff /* we consider these bits "section type" */
- /* fake section for absolute symbols, *not* part of the section linked list */
- static struct section absolute_sect;
- struct reloc {
- /* nasm internal data */
- struct reloc *next;
- /* data that goes into the file */
- int32_t addr; /* op's offset in section */
- uint32_t snum:24, /* contains symbol index if
- ** ext otherwise in-file
- ** section number */
- pcrel:1, /* relative relocation */
- length:2, /* 0=byte, 1=word, 2=int32_t, 3=int64_t */
- ext:1, /* external symbol referenced */
- type:4; /* reloc type */
- };
- #define R_ABS 0 /* absolute relocation */
- #define R_SCATTERED 0x80000000 /* reloc entry is scattered if
- ** highest bit == 1 */
- struct symbol {
- /* nasm internal data */
- struct rbtree symv[2]; /* All/global symbol rbtrees; "key" contains the
- symbol offset. */
- struct symbol *next; /* next symbol in the list */
- char *name; /* name of this symbol */
- int32_t initial_snum; /* symbol number used above in reloc */
- int32_t snum; /* true snum for reloc */
- /* data that goes into the file */
- uint32_t strx; /* string table index */
- uint8_t type; /* symbol type */
- uint8_t sect; /* NO_SECT or section number */
- uint16_t desc; /* for stab debugging, 0 for us */
- };
- /* symbol type bits */
- #define N_EXT 0x01 /* global or external symbol */
- #define N_PEXT 0x10 /* private external symbol */
- #define N_UNDF 0x0 /* undefined symbol | n_sect == */
- #define N_ABS 0x2 /* absolute symbol | NO_SECT */
- #define N_SECT 0xe /* defined symbol, n_sect holds
- ** section number */
- #define N_TYPE 0x0e /* type bit mask */
- #define DEFAULT_SECTION_ALIGNMENT 0 /* byte (i.e. no) alignment */
- /* special section number values */
- #define NO_SECT 0 /* no section, invalid */
- #define MAX_SECT 255 /* maximum number of sections */
- static struct section *sects, **sectstail, **sectstab;
- static struct symbol *syms, **symstail;
- static uint32_t nsyms;
- /* These variables are set by macho_layout_symbols() to organize
- the symbol table and string table in order the dynamic linker
- expects. They are then used in macho_write() to put out the
- symbols and strings in that order.
- The order of the symbol table is:
- local symbols
- defined external symbols (sorted by name)
- undefined external symbols (sorted by name)
- The order of the string table is:
- strings for external symbols
- strings for local symbols
- */
- static uint32_t ilocalsym = 0;
- static uint32_t iextdefsym = 0;
- static uint32_t iundefsym = 0;
- static uint32_t nlocalsym;
- static uint32_t nextdefsym;
- static uint32_t nundefsym;
- static struct symbol **extdefsyms = NULL;
- static struct symbol **undefsyms = NULL;
- static struct RAA *extsyms;
- static struct SAA *strs;
- static uint32_t strslen;
- /* Global file information. This should be cleaned up into either
- a structure or as function arguments. */
- static uint32_t head_ncmds = 0;
- static uint32_t head_sizeofcmds = 0;
- static uint32_t head_flags = 0;
- static uint64_t seg_filesize = 0;
- static uint64_t seg_vmsize = 0;
- static uint32_t seg_nsects = 0;
- static uint64_t rel_padcnt = 0;
- /*
- * Functions for handling fixed-length zero-padded string
- * fields, that may or may not be null-terminated.
- */
- /* Copy a string into a zero-padded fixed-length field */
- #define xstrncpy(xdst, xsrc) strncpy(xdst, xsrc, sizeof(xdst))
- /* Compare a fixed-length field with a string */
- #define xstrncmp(xdst, xsrc) strncmp(xdst, xsrc, sizeof(xdst))
- #define alignint32_t(x) \
- ALIGN(x, sizeof(int32_t)) /* align x to int32_t boundary */
- #define alignint64_t(x) \
- ALIGN(x, sizeof(int64_t)) /* align x to int64_t boundary */
- #define alignptr(x) \
- ALIGN(x, fmt.ptrsize) /* align x to output format width */
- static struct hash_table section_by_name;
- static struct RAAPTR *section_by_index;
- static struct section * never_null
- find_or_add_section(const char *segname, const char *sectname)
- {
- struct hash_insert hi;
- void **sp;
- struct section *s;
- char sect[34];
- snprintf(sect, sizeof sect, "%-16s,%-16s", segname, sectname);
- sp = hash_find(§ion_by_name, sect, &hi);
- if (sp)
- return (struct section *)(*sp);
- s = nasm_zalloc(sizeof *s);
- xstrncpy(s->segname, segname);
- xstrncpy(s->sectname, sectname);
- xstrncpy(s->namestr, sect);
- hash_add(&hi, s->namestr, s);
- s->index = s->subsection = seg_alloc();
- section_by_index = raa_write_ptr(section_by_index, s->index >> 1, s);
- return s;
- }
- static inline bool is_new_section(const struct section *s)
- {
- return !s->data;
- }
- static struct section *get_section_by_name(const char *segname,
- const char *sectname)
- {
- char sect[34];
- void **sp;
- snprintf(sect, sizeof sect, "%-16s,%-16s", segname, sectname);
- sp = hash_find(§ion_by_name, sect, NULL);
- return sp ? (struct section *)(*sp) : NULL;
- }
- static struct section *get_section_by_index(int32_t index)
- {
- if (index < 0 || index >= SEG_ABS || (index & 1))
- return NULL;
- return raa_read_ptr(section_by_index, index >> 1);
- }
- struct dir_list {
- struct dir_list *next;
- struct dir_list *last;
- const char *dir_name;
- uint32_t dir;
- };
- struct file_list {
- struct file_list *next;
- struct file_list *last;
- const char *file_name;
- uint32_t file;
- struct dir_list *dir;
- };
- struct dw_sect_list {
- struct SAA *psaa;
- int32_t section;
- uint32_t line;
- uint64_t offset;
- uint32_t file;
- struct dw_sect_list *next;
- struct dw_sect_list *last;
- };
- struct section_info {
- uint64_t size;
- int32_t secto;
- };
- #define DW_LN_BASE (-5)
- #define DW_LN_RANGE 14
- #define DW_OPCODE_BASE 13
- #define DW_MAX_LN (DW_LN_BASE + DW_LN_RANGE)
- #define DW_MAX_SP_OPCODE 256
- static struct file_list *dw_head_file = 0, *dw_cur_file = 0, **dw_last_file_next = NULL;
- static struct dir_list *dw_head_dir = 0, **dw_last_dir_next = NULL;
- static struct dw_sect_list *dw_head_sect = 0, *dw_cur_sect = 0, *dw_last_sect = 0;
- static uint32_t cur_line = 0, dw_num_files = 0, dw_num_dirs = 0, dw_num_sects = 0;
- static bool dbg_immcall = false;
- static const char *module_name = NULL;
- /*
- * Special section numbers which are used to define Mach-O special
- * symbols, which can be used with WRT to provide PIC relocation
- * types.
- */
- static int32_t macho_tlvp_sect;
- static int32_t macho_gotpcrel_sect;
- static void macho_init(void)
- {
- module_name = inname;
- sects = NULL;
- sectstail = §s;
- /* Fake section for absolute symbols */
- absolute_sect.index = NO_SEG;
- syms = NULL;
- symstail = &syms;
- nsyms = 0;
- nlocalsym = 0;
- nextdefsym = 0;
- nundefsym = 0;
- extsyms = raa_init();
- strs = saa_init(1L);
- section_by_index = raa_init_ptr();
- hash_init(§ion_by_name, HASH_MEDIUM);
- /* string table starts with a zero byte so index 0 is an empty string */
- saa_wbytes(strs, zero_buffer, 1);
- strslen = 1;
- /* add special symbol for TLVP */
- macho_tlvp_sect = seg_alloc() + 1;
- backend_label("..tlvp", macho_tlvp_sect, 0L);
- }
- static void sect_write(struct section *sect,
- const uint8_t *data, uint32_t len)
- {
- saa_wbytes(sect->data, data, len);
- sect->size += len;
- }
- /*
- * Find a suitable global symbol for a ..gotpcrel or ..tlvp reference
- */
- static struct symbol *macho_find_sym(struct section *s, uint64_t offset,
- bool global, bool exact)
- {
- struct rbtree *srb;
- srb = rb_search(s->syms[global], offset);
- if (!srb || (exact && srb->key != offset)) {
- nasm_error(ERR_NONFATAL, "unable to find a suitable%s%s symbol"
- " for this reference",
- global ? " global" : "",
- s == &absolute_sect ? " absolute " : "");
- return NULL;
- }
- return container_of(srb - global, struct symbol, symv);
- }
- static int64_t add_reloc(struct section *sect, int32_t section,
- int64_t offset,
- enum reltype reltype, int bytes)
- {
- struct reloc *r;
- struct section *s;
- int32_t fi;
- int64_t adjust;
- /* Double check this is a valid relocation type for this platform */
- nasm_assert(reltype <= fmt.maxreltype);
- /* the current end of the section will be the symbol's address for
- ** now, might have to be fixed by macho_fixup_relocs() later on. make
- ** sure we don't make the symbol scattered by setting the highest
- ** bit by accident */
- r = nasm_malloc(sizeof(struct reloc));
- r->addr = sect->size & ~R_SCATTERED;
- r->ext = 1;
- adjust = 0;
- /* match byte count 1, 2, 4, 8 to length codes 0, 1, 2, 3 respectively */
- r->length = ilog2_32(bytes);
- /* set default relocation values */
- r->type = fmt.reloc_abs;
- r->pcrel = 0;
- r->snum = R_ABS;
- s = get_section_by_index(section);
- fi = s ? s->fileindex : NO_SECT;
- /* absolute relocation */
- switch (reltype) {
- case RL_ABS:
- if (section == NO_SEG) {
- /* absolute (can this even happen?) */
- r->ext = 0;
- } else if (fi == NO_SECT) {
- /* external */
- r->snum = raa_read(extsyms, section);
- } else {
- /* local */
- r->ext = 0;
- r->snum = fi;
- }
- break;
- case RL_REL:
- case RL_BRANCH:
- r->type = fmt.reloc_rel;
- r->pcrel = 1;
- if (section == NO_SEG) {
- /* may optionally be converted below by fmt.forcesym */
- r->ext = 0;
- } else if (fi == NO_SECT) {
- /* external */
- sect->extreloc = 1;
- r->snum = raa_read(extsyms, section);
- if (reltype == RL_BRANCH)
- r->type = X86_64_RELOC_BRANCH;
- } else {
- /* local */
- r->ext = 0;
- r->snum = fi;
- if (reltype == RL_BRANCH)
- r->type = X86_64_RELOC_BRANCH;
- }
- break;
- case RL_SUB: /* obsolete */
- nasm_error(ERR_WARNING, "relcation with subtraction"
- "becomes to be obsolete");
- r->ext = 0;
- r->type = X86_64_RELOC_SUBTRACTOR;
- break;
- case RL_GOT:
- r->type = X86_64_RELOC_GOT;
- goto needsym;
- case RL_GOTLOAD:
- r->type = X86_64_RELOC_GOT_LOAD;
- goto needsym;
- case RL_TLV:
- r->type = fmt.reloc_tlv;
- goto needsym;
- needsym:
- r->pcrel = (fmt.ptrsize == 8 ? 1 : 0);
- if (section == NO_SEG) {
- nasm_error(ERR_NONFATAL, "Unsupported use of use of WRT");
- goto bail;
- } else if (fi == NO_SECT) {
- /* external */
- r->snum = raa_read(extsyms, section);
- } else {
- /* internal - GOTPCREL doesn't need to be in global */
- struct symbol *sym = macho_find_sym(s, offset,
- false, /* reltype != RL_TLV */
- true);
- if (!sym) {
- nasm_error(ERR_NONFATAL, "Symbol for WRT not found");
- goto bail;
- }
- adjust -= sym->symv[0].key;
- r->snum = sym->initial_snum;
- }
- break;
- }
- /*
- * For 64-bit Mach-O, force a symbol reference if at all possible
- * Allow for r->snum == R_ABS by searching absolute_sect
- */
- if (!r->ext && fmt.forcesym) {
- struct symbol *sym = macho_find_sym(s ? s : &absolute_sect,
- offset, false, false);
- if (sym) {
- adjust -= sym->symv[0].key;
- r->snum = sym->initial_snum;
- r->ext = 1;
- }
- }
- if (r->pcrel)
- adjust += ((r->ext && fmt.ptrsize == 8) ? bytes : -(int64_t)sect->size);
- /* NeXT as puts relocs in reversed order (address-wise) into the
- ** files, so we do the same, doesn't seem to make much of a
- ** difference either way */
- r->next = sect->relocs;
- sect->relocs = r;
- if (r->ext)
- sect->extreloc = 1;
- ++sect->nreloc;
- return adjust;
- bail:
- nasm_free(r);
- return 0;
- }
- static void macho_output(int32_t secto, const void *data,
- enum out_type type, uint64_t size,
- int32_t section, int32_t wrt)
- {
- struct section *s;
- int64_t addr, offset;
- uint8_t mydata[16], *p;
- bool is_bss;
- enum reltype reltype;
- if (secto == NO_SEG) {
- if (type != OUT_RESERVE)
- nasm_error(ERR_NONFATAL, "attempt to assemble code in "
- "[ABSOLUTE] space");
- return;
- }
- s = get_section_by_index(secto);
- if (!s) {
- nasm_error(ERR_WARNING, "attempt to assemble code in"
- " section %d: defaulting to `.text'", secto);
- s = get_section_by_name("__TEXT", "__text");
- /* should never happen */
- if (!s)
- nasm_panic(0, "text section not found");
- }
- /* debug code generation only for sections tagged with
- * instruction attribute */
- if (s->flags & S_ATTR_SOME_INSTRUCTIONS)
- {
- struct section_info sinfo;
- sinfo.size = s->size;
- sinfo.secto = secto;
- dfmt->debug_output(0, &sinfo);
- }
- is_bss = (s->flags & SECTION_TYPE) == S_ZEROFILL;
- if (is_bss && type != OUT_RESERVE) {
- nasm_error(ERR_WARNING, "attempt to initialize memory in "
- "BSS section: ignored");
- /* FIXME */
- nasm_error(ERR_WARNING, "section size may be negative"
- "with address symbols");
- s->size += realsize(type, size);
- return;
- }
- memset(mydata, 0, sizeof(mydata));
- switch (type) {
- case OUT_RESERVE:
- if (!is_bss) {
- nasm_error(ERR_WARNING, "uninitialized space declared in"
- " %s,%s section: zeroing", s->segname, s->sectname);
- sect_write(s, NULL, size);
- } else
- s->size += size;
- break;
- case OUT_RAWDATA:
- if (section != NO_SEG)
- nasm_panic(0, "OUT_RAWDATA with other than NO_SEG");
- sect_write(s, data, size);
- break;
- case OUT_ADDRESS:
- {
- int asize = abs((int)size);
- addr = *(int64_t *)data;
- if (section != NO_SEG) {
- if (section % 2) {
- nasm_error(ERR_NONFATAL, "Mach-O format does not support"
- " section base references");
- } else if (wrt == NO_SEG) {
- if (fmt.ptrsize == 8 && asize != 8) {
- nasm_error(ERR_NONFATAL,
- "Mach-O 64-bit format does not support"
- " 32-bit absolute addresses");
- } else {
- addr += add_reloc(s, section, addr, RL_ABS, asize);
- }
- } else if (wrt == macho_tlvp_sect && fmt.ptrsize != 8 &&
- asize == (int) fmt.ptrsize) {
- addr += add_reloc(s, section, addr, RL_TLV, asize);
- } else {
- nasm_error(ERR_NONFATAL, "Mach-O format does not support"
- " this use of WRT");
- }
- }
- p = mydata;
- WRITEADDR(p, addr, asize);
- sect_write(s, mydata, asize);
- break;
- }
- case OUT_REL1ADR:
- case OUT_REL2ADR:
- p = mydata;
- offset = *(int64_t *)data;
- addr = offset - size;
- if (section != NO_SEG && section % 2) {
- nasm_error(ERR_NONFATAL, "Mach-O format does not support"
- " section base references");
- } else if (fmt.ptrsize == 8) {
- nasm_error(ERR_NONFATAL, "Unsupported non-32-bit"
- " Macho-O relocation [2]");
- } else if (wrt != NO_SEG) {
- nasm_error(ERR_NONFATAL, "Mach-O format does not support"
- " this use of WRT");
- wrt = NO_SEG; /* we can at least _try_ to continue */
- } else {
- addr += add_reloc(s, section, addr+size, RL_REL,
- type == OUT_REL1ADR ? 1 : 2);
- }
- WRITESHORT(p, addr);
- sect_write(s, mydata, type == OUT_REL1ADR ? 1 : 2);
- break;
- case OUT_REL4ADR:
- case OUT_REL8ADR:
- p = mydata;
- offset = *(int64_t *)data;
- addr = offset - size;
- reltype = RL_REL;
- if (section != NO_SEG && section % 2) {
- nasm_error(ERR_NONFATAL, "Mach-O format does not support"
- " section base references");
- } else if (wrt == NO_SEG) {
- if (fmt.ptrsize == 8 &&
- (s->flags & S_ATTR_SOME_INSTRUCTIONS)) {
- uint8_t opcode[2];
- opcode[0] = opcode[1] = 0;
- /* HACK: Retrieve instruction opcode */
- if (likely(s->data->datalen >= 2)) {
- saa_fread(s->data, s->data->datalen-2, opcode, 2);
- } else if (s->data->datalen == 1) {
- saa_fread(s->data, 0, opcode+1, 1);
- }
- if ((opcode[0] != 0x0f && (opcode[1] & 0xfe) == 0xe8) ||
- (opcode[0] == 0x0f && (opcode[1] & 0xf0) == 0x80)) {
- /* Direct call, jmp, or jcc */
- reltype = RL_BRANCH;
- }
- }
- } else if (wrt == macho_gotpcrel_sect) {
- reltype = RL_GOT;
- if ((s->flags & S_ATTR_SOME_INSTRUCTIONS) &&
- s->data->datalen >= 3) {
- uint8_t gotload[3];
- /* HACK: Retrieve instruction opcode */
- saa_fread(s->data, s->data->datalen-3, gotload, 3);
- if ((gotload[0] & 0xf8) == 0x48 &&
- gotload[1] == 0x8b &&
- (gotload[2] & 0307) == 0005) {
- /* movq <reg>,[rel sym wrt ..gotpcrel] */
- reltype = RL_GOTLOAD;
- }
- }
- } else if (wrt == macho_tlvp_sect && fmt.ptrsize == 8) {
- reltype = RL_TLV;
- } else {
- nasm_error(ERR_NONFATAL, "Mach-O format does not support"
- " this use of WRT");
- /* continue with RL_REL */
- }
- addr += add_reloc(s, section, offset, reltype,
- type == OUT_REL4ADR ? 4 : 8);
- WRITELONG(p, addr);
- sect_write(s, mydata, type == OUT_REL4ADR ? 4 : 8);
- break;
- default:
- nasm_error(ERR_NONFATAL, "Unrepresentable relocation in Mach-O");
- break;
- }
- }
- /* Translation table from traditional Unix section names to Mach-O */
- static const struct sectmap {
- const char *nasmsect;
- const char *segname;
- const char *sectname;
- const uint32_t flags;
- } sectmap[] = {
- {".text", "__TEXT", "__text",
- S_REGULAR|S_ATTR_SOME_INSTRUCTIONS|S_ATTR_PURE_INSTRUCTIONS},
- {".data", "__DATA", "__data", S_REGULAR},
- {".rodata", "__DATA", "__const", S_REGULAR},
- {".bss", "__DATA", "__bss", S_ZEROFILL},
- {".debug_abbrev", "__DWARF", "__debug_abbrev", S_ATTR_DEBUG},
- {".debug_info", "__DWARF", "__debug_info", S_ATTR_DEBUG},
- {".debug_line", "__DWARF", "__debug_line", S_ATTR_DEBUG},
- {".debug_str", "__DWARF", "__debug_str", S_ATTR_DEBUG},
- {NULL, NULL, NULL, 0}
- };
- #define NO_TYPE S_NASM_TYPE_MASK
- /* Section type or attribute directives */
- static const struct sect_attribs {
- const char *name;
- uint32_t flags;
- } sect_attribs[] = {
- { "data", S_REGULAR },
- { "code", S_REGULAR|S_ATTR_SOME_INSTRUCTIONS|S_ATTR_PURE_INSTRUCTIONS },
- { "mixed", S_REGULAR|S_ATTR_SOME_INSTRUCTIONS },
- { "bss", S_ZEROFILL },
- { "zerofill", S_ZEROFILL },
- { "no_dead_strip", NO_TYPE|S_ATTR_NO_DEAD_STRIP },
- { "live_support", NO_TYPE|S_ATTR_LIVE_SUPPORT },
- { "strip_static_syms", NO_TYPE|S_ATTR_STRIP_STATIC_SYMS },
- { "debug", NO_TYPE|S_ATTR_DEBUG },
- { NULL, 0 }
- };
- static int32_t macho_section(char *name, int pass, int *bits)
- {
- char *sectionAttributes;
- const struct sectmap *sm;
- struct section *s;
- const char *section, *segment;
- uint32_t flags;
- const struct sect_attribs *sa;
- char *currentAttribute;
- char *comma;
- bool new_seg;
- (void)pass;
- /* Default to the appropriate number of bits. */
- if (!name) {
- *bits = fmt.ptrsize << 3;
- name = ".text";
- sectionAttributes = NULL;
- } else {
- sectionAttributes = name;
- name = nasm_strsep(§ionAttributes, " \t");
- }
- section = segment = NULL;
- flags = 0;
- comma = strchr(name, ',');
- if (comma) {
- int len;
- *comma = '\0';
- segment = name;
- section = comma+1;
- len = strlen(segment);
- if (len == 0) {
- nasm_error(ERR_NONFATAL, "empty segment name\n");
- } else if (len > 16) {
- nasm_error(ERR_NONFATAL, "segment name %s too long\n", segment);
- }
- len = strlen(section);
- if (len == 0) {
- nasm_error(ERR_NONFATAL, "empty section name\n");
- } else if (len > 16) {
- nasm_error(ERR_NONFATAL, "section name %s too long\n", section);
- }
- if (!strcmp(section, "__text")) {
- flags = S_REGULAR | S_ATTR_SOME_INSTRUCTIONS |
- S_ATTR_PURE_INSTRUCTIONS;
- } else if (!strcmp(section, "__bss")) {
- flags = S_ZEROFILL;
- } else {
- flags = S_REGULAR;
- }
- } else {
- for (sm = sectmap; sm->nasmsect != NULL; ++sm) {
- /* make lookup into section name translation table */
- if (!strcmp(name, sm->nasmsect)) {
- segment = sm->segname;
- section = sm->sectname;
- flags = sm->flags;
- goto found;
- }
- }
- nasm_error(ERR_NONFATAL, "unknown section name\n");
- return NO_SEG;
- }
- found:
- /* try to find section with that name, or create it */
- s = find_or_add_section(segment, section);
- new_seg = is_new_section(s);
- /* initialize it if it is a brand new section */
- if (new_seg) {
- *sectstail = s;
- sectstail = &s->next;
- s->data = saa_init(1L);
- s->fileindex = ++seg_nsects;
- s->align = -1;
- s->pad = -1;
- s->offset = -1;
- s->by_name = false;
- s->size = 0;
- s->nreloc = 0;
- s->flags = flags;
- }
- if (comma)
- *comma = ','; /* Restore comma */
- s->by_name = s->by_name || comma; /* Was specified by name */
- flags = NO_TYPE;
- while (sectionAttributes &&
- (currentAttribute = nasm_strsep(§ionAttributes, " \t"))) {
- if (!*currentAttribute)
- continue;
- if (!nasm_strnicmp("align=", currentAttribute, 6)) {
- char *end;
- int newAlignment, value;
- value = strtoul(currentAttribute + 6, (char**)&end, 0);
- newAlignment = alignlog2_32(value);
- if (0 != *end) {
- nasm_error(ERR_NONFATAL,
- "unknown or missing alignment value \"%s\" "
- "specified for section \"%s\"",
- currentAttribute + 6,
- name);
- } else if (0 > newAlignment) {
- nasm_error(ERR_NONFATAL,
- "alignment of %d (for section \"%s\") is not "
- "a power of two",
- value,
- name);
- }
- if (s->align < newAlignment)
- s->align = newAlignment;
- } else {
- for (sa = sect_attribs; sa->name; sa++) {
- if (!nasm_stricmp(sa->name, currentAttribute)) {
- if ((sa->flags & S_NASM_TYPE_MASK) != NO_TYPE) {
- flags = (flags & ~S_NASM_TYPE_MASK)
- | (sa->flags & S_NASM_TYPE_MASK);
- }
- flags |= sa->flags & ~S_NASM_TYPE_MASK;
- break;
- }
- }
- if (!sa->name) {
- nasm_error(ERR_NONFATAL,
- "unknown section attribute %s for section %s",
- currentAttribute, name);
- }
- }
- }
- if ((flags & S_NASM_TYPE_MASK) != NO_TYPE) {
- if (!new_seg && ((s->flags ^ flags) & S_NASM_TYPE_MASK)) {
- nasm_error(ERR_NONFATAL,
- "inconsistent section attributes for section %s\n",
- name);
- } else {
- s->flags = (s->flags & ~S_NASM_TYPE_MASK) | flags;
- }
- } else {
- s->flags |= flags & ~S_NASM_TYPE_MASK;
- }
- return s->subsection;
- }
- static int32_t macho_herelabel(const char *name, enum label_type type,
- int32_t section, int32_t *subsection,
- bool *copyoffset)
- {
- struct section *s;
- int32_t subsec;
- (void)name;
- if (!(head_flags & MH_SUBSECTIONS_VIA_SYMBOLS))
- return section;
- /* No subsection only for local labels */
- if (type == LBL_LOCAL)
- return section;
- s = get_section_by_index(section);
- if (!s)
- return section;
- subsec = *subsection;
- if (subsec == NO_SEG) {
- /* Allocate a new subsection index */
- subsec = *subsection = seg_alloc();
- section_by_index = raa_write_ptr(section_by_index, subsec >> 1, s);
- }
- s->subsection = subsec;
- *copyoffset = true; /* Maintain previous offset */
- return subsec;
- }
- static void macho_symdef(char *name, int32_t section, int64_t offset,
- int is_global, char *special)
- {
- struct symbol *sym;
- struct section *s;
- bool special_used = false;
- #if defined(DEBUG) && DEBUG>2
- nasm_error(ERR_DEBUG,
- " macho_symdef: %s, pass0=%d, passn=%"PRId64", sec=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n",
- name, pass0, passn, section, offset, is_global, special);
- #endif
- if (is_global == 3) {
- if (special) {
- int n = strcspn(special, " \t");
- if (!nasm_strnicmp(special, "private_extern", n)) {
- for (sym = syms; sym != NULL; sym = sym->next) {
- if (!strcmp(name, sym->name)) {
- if (sym->type & N_PEXT)
- return; /* nothing to be done */
- else
- break;
- }
- }
- }
- }
- nasm_error(ERR_NONFATAL, "The Mach-O format does not "
- "(yet) support forward reference fixups.");
- return;
- }
- if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
- /*
- * This is a NASM special symbol. We never allow it into
- * the Macho-O symbol table, even if it's a valid one. If it
- * _isn't_ a valid one, we should barf immediately.
- */
- if (strcmp(name, "..gotpcrel") && strcmp(name, "..tlvp"))
- nasm_error(ERR_NONFATAL, "unrecognized special symbol `%s'", name);
- return;
- }
- sym = *symstail = nasm_zalloc(sizeof(struct symbol));
- sym->next = NULL;
- symstail = &sym->next;
- sym->name = name;
- sym->strx = strslen;
- sym->type = 0;
- sym->desc = 0;
- sym->symv[0].key = offset;
- sym->symv[1].key = offset;
- sym->initial_snum = -1;
- /* external and common symbols get N_EXT */
- if (is_global != 0) {
- sym->type |= N_EXT;
- }
- if (is_global == 1) {
- /* check special to see if the global symbol shall be marked as private external: N_PEXT */
- if (special) {
- int n = strcspn(special, " \t");
- if (!nasm_strnicmp(special, "private_extern", n))
- sym->type |= N_PEXT;
- else
- nasm_error(ERR_NONFATAL, "unrecognised symbol type `%.*s'", n, special);
- }
- special_used = true;
- }
- /* track the initially allocated symbol number for use in future fix-ups */
- sym->initial_snum = nsyms;
- if (section == NO_SEG) {
- /* symbols in no section get absolute */
- sym->type |= N_ABS;
- sym->sect = NO_SECT;
- s = &absolute_sect;
- } else {
- s = get_section_by_index(section);
- sym->type |= N_SECT;
- /* get the in-file index of the section the symbol was defined in */
- sym->sect = s ? s->fileindex : NO_SECT;
- if (!s) {
- /* remember symbol number of references to external
- ** symbols, this works because every external symbol gets
- ** its own section number allocated internally by nasm and
- ** can so be used as a key */
- extsyms = raa_write(extsyms, section, nsyms);
- switch (is_global) {
- case 1:
- case 2:
- /* there isn't actually a difference between global
- ** and common symbols, both even have their size in
- ** sym->symv[0].key */
- sym->type = N_EXT;
- break;
- default:
- /* give an error on unfound section if it's not an
- ** external or common symbol (assemble_file() does a
- ** seg_alloc() on every call for them) */
- nasm_panic(0, "in-file index for section %d not found, is_global = %d", section, is_global);
- break;
- }
- }
- }
- if (s) {
- s->syms[0] = rb_insert(s->syms[0], &sym->symv[0]);
- if (is_global)
- s->syms[1] = rb_insert(s->syms[1], &sym->symv[1]);
- }
- ++nsyms;
- if (special && !special_used)
- nasm_error(ERR_NONFATAL, "no special symbol features supported here");
- }
- static void macho_sectalign(int32_t seg, unsigned int value)
- {
- struct section *s;
- int align;
- nasm_assert(!(seg & 1));
- s = get_section_by_index(seg);
- if (!s || !is_power2(value))
- return;
- align = alignlog2_32(value);
- if (s->align < align)
- s->align = align;
- }
- static int32_t macho_segbase(int32_t section)
- {
- return section;
- }
- extern macros_t macho_stdmac[];
- /* Comparison function for qsort symbol layout. */
- static int layout_compare (const struct symbol **s1,
- const struct symbol **s2)
- {
- return (strcmp ((*s1)->name, (*s2)->name));
- }
- /* The native assembler does a few things in a similar function
- * Remove temporary labels
- * Sort symbols according to local, external, undefined (by name)
- * Order the string table
- We do not remove temporary labels right now.
- numsyms is the total number of symbols we have. strtabsize is the
- number entries in the string table. */
- static void macho_layout_symbols (uint32_t *numsyms,
- uint32_t *strtabsize)
- {
- struct symbol *sym, **symp;
- uint32_t i,j;
- *numsyms = 0;
- *strtabsize = sizeof (char);
- symp = &syms;
- while ((sym = *symp)) {
- /* Undefined symbols are now external. */
- if (sym->type == N_UNDF)
- sym->type |= N_EXT;
- if ((sym->type & N_EXT) == 0) {
- sym->snum = *numsyms;
- *numsyms = *numsyms + 1;
- nlocalsym++;
- }
- else {
- if ((sym->type & N_TYPE) != N_UNDF) {
- nextdefsym++;
- } else {
- nundefsym++;
- }
- /* If we handle debug info we'll want
- to check for it here instead of just
- adding the symbol to the string table. */
- sym->strx = *strtabsize;
- saa_wbytes (strs, sym->name, (int32_t)(strlen(sym->name) + 1));
- *strtabsize += strlen(sym->name) + 1;
- }
- symp = &(sym->next);
- }
- /* Next, sort the symbols. Most of this code is a direct translation from
- the Apple cctools symbol layout. We need to keep compatibility with that. */
- /* Set the indexes for symbol groups into the symbol table */
- ilocalsym = 0;
- iextdefsym = nlocalsym;
- iundefsym = nlocalsym + nextdefsym;
- /* allocate arrays for sorting externals by name */
- extdefsyms = nasm_malloc(nextdefsym * sizeof(struct symbol *));
- undefsyms = nasm_malloc(nundefsym * sizeof(struct symbol *));
- i = 0;
- j = 0;
- symp = &syms;
- while ((sym = *symp)) {
- if((sym->type & N_EXT) == 0) {
- sym->strx = *strtabsize;
- saa_wbytes (strs, sym->name, (int32_t)(strlen (sym->name) + 1));
- *strtabsize += strlen(sym->name) + 1;
- }
- else {
- if ((sym->type & N_TYPE) != N_UNDF) {
- extdefsyms[i++] = sym;
- } else {
- undefsyms[j++] = sym;
- }
- }
- symp = &(sym->next);
- }
- qsort(extdefsyms, nextdefsym, sizeof(struct symbol *),
- (int (*)(const void *, const void *))layout_compare);
- qsort(undefsyms, nundefsym, sizeof(struct symbol *),
- (int (*)(const void *, const void *))layout_compare);
- for(i = 0; i < nextdefsym; i++) {
- extdefsyms[i]->snum = *numsyms;
- *numsyms += 1;
- }
- for(j = 0; j < nundefsym; j++) {
- undefsyms[j]->snum = *numsyms;
- *numsyms += 1;
- }
- }
- /* Calculate some values we'll need for writing later. */
- static void macho_calculate_sizes (void)
- {
- struct section *s;
- int fi;
- /* count sections and calculate in-memory and in-file offsets */
- for (s = sects; s != NULL; s = s->next) {
- uint64_t newaddr;
- /* recalculate segment address based on alignment and vm size */
- s->addr = seg_vmsize;
- /* we need section alignment to calculate final section address */
- if (s->align == -1)
- s->align = DEFAULT_SECTION_ALIGNMENT;
- newaddr = ALIGN(s->addr, UINT64_C(1) << s->align);
- s->addr = newaddr;
- seg_vmsize = newaddr + s->size;
- /* zerofill sections aren't actually written to the file */
- if ((s->flags & SECTION_TYPE) != S_ZEROFILL) {
- /*
- * LLVM/Xcode as always aligns the section data to 4
- * bytes; there is a comment in the LLVM source code that
- * perhaps aligning to pointer size would be better.
- */
- s->pad = ALIGN(seg_filesize, 4) - seg_filesize;
- s->offset = seg_filesize + s->pad;
- seg_filesize += s->size + s->pad;
- /* filesize and vmsize needs to be aligned */
- seg_vmsize += s->pad;
- }
- }
- /* calculate size of all headers, load commands and sections to
- ** get a pointer to the start of all the raw data */
- if (seg_nsects > 0) {
- ++head_ncmds;
- head_sizeofcmds += fmt.segcmd_size + seg_nsects * fmt.sectcmd_size;
- }
- if (nsyms > 0) {
- ++head_ncmds;
- head_sizeofcmds += MACHO_SYMCMD_SIZE;
- }
- if (seg_nsects > MAX_SECT) {
- nasm_fatal(0, "MachO output is limited to %d sections\n",
- MAX_SECT);
- }
- /* Create a table of sections by file index to avoid linear search */
- sectstab = nasm_malloc((seg_nsects + 1) * sizeof(*sectstab));
- sectstab[NO_SECT] = &absolute_sect;
- for (s = sects, fi = 1; s != NULL; s = s->next, fi++)
- sectstab[fi] = s;
- }
- /* Write out the header information for the file. */
- static void macho_write_header (void)
- {
- fwriteint32_t(fmt.mh_magic, ofile); /* magic */
- fwriteint32_t(fmt.cpu_type, ofile); /* CPU type */
- fwriteint32_t(CPU_SUBTYPE_I386_ALL, ofile); /* CPU subtype */
- fwriteint32_t(MH_OBJECT, ofile); /* Mach-O file type */
- fwriteint32_t(head_ncmds, ofile); /* number of load commands */
- fwriteint32_t(head_sizeofcmds, ofile); /* size of load commands */
- fwriteint32_t(head_flags, ofile); /* flags, if any */
- fwritezero(fmt.header_size - 7*4, ofile); /* reserved fields */
- }
- /* Write out the segment load command at offset. */
- static uint32_t macho_write_segment (uint64_t offset)
- {
- uint64_t rel_base = alignptr(offset + seg_filesize);
- uint32_t s_reloff = 0;
- struct section *s;
- fwriteint32_t(fmt.lc_segment, ofile); /* cmd == LC_SEGMENT_64 */
- /* size of load command including section load commands */
- fwriteint32_t(fmt.segcmd_size + seg_nsects * fmt.sectcmd_size,
- ofile);
- /* in an MH_OBJECT file all sections are in one unnamed (name
- ** all zeros) segment */
- fwritezero(16, ofile);
- fwriteptr(0, ofile); /* in-memory offset */
- fwriteptr(seg_vmsize, ofile); /* in-memory size */
- fwriteptr(offset, ofile); /* in-file offset to data */
- fwriteptr(seg_filesize, ofile); /* in-file size */
- fwriteint32_t(VM_PROT_DEFAULT, ofile); /* maximum vm protection */
- fwriteint32_t(VM_PROT_DEFAULT, ofile); /* initial vm protection */
- fwriteint32_t(seg_nsects, ofile); /* number of sections */
- fwriteint32_t(0, ofile); /* no flags */
- /* emit section headers */
- for (s = sects; s != NULL; s = s->next) {
- if (s->nreloc) {
- nasm_assert((s->flags & SECTION_TYPE) != S_ZEROFILL);
- s->flags |= S_ATTR_LOC_RELOC;
- if (s->extreloc)
- s->flags |= S_ATTR_EXT_RELOC;
- } else if (!xstrncmp(s->segname, "__DATA") &&
- !xstrncmp(s->sectname, "__const") &&
- !s->by_name &&
- !get_section_by_name("__TEXT", "__const")) {
- /*
- * The MachO equivalent to .rodata can be either
- * __DATA,__const or __TEXT,__const; the latter only if
- * there are no relocations. However, when mixed it is
- * better to specify the segments explicitly.
- */
- xstrncpy(s->segname, "__TEXT");
- }
- nasm_write(s->sectname, sizeof(s->sectname), ofile);
- nasm_write(s->segname, sizeof(s->segname), ofile);
- fwriteptr(s->addr, ofile);
- fwriteptr(s->size, ofile);
- /* dummy data for zerofill sections or proper values */
- if ((s->flags & SECTION_TYPE) != S_ZEROFILL) {
- nasm_assert(s->pad != (uint32_t)-1);
- offset += s->pad;
- fwriteint32_t(offset, ofile);
- offset += s->size;
- /* Write out section alignment, as a power of two.
- e.g. 32-bit word alignment would be 2 (2^2 = 4). */
- fwriteint32_t(s->align, ofile);
- /* To be compatible with cctools as we emit
- a zero reloff if we have no relocations. */
- fwriteint32_t(s->nreloc ? rel_base + s_reloff : 0, ofile);
- fwriteint32_t(s->nreloc, ofile);
- s_reloff += s->nreloc * MACHO_RELINFO_SIZE;
- } else {
- fwriteint32_t(0, ofile);
- fwriteint32_t(s->align, ofile);
- fwriteint32_t(0, ofile);
- fwriteint32_t(0, ofile);
- }
- fwriteint32_t(s->flags, ofile); /* flags */
- fwriteint32_t(0, ofile); /* reserved */
- fwriteptr(0, ofile); /* reserved */
- }
- rel_padcnt = rel_base - offset;
- offset = rel_base + s_reloff;
- return offset;
- }
- /* For a given chain of relocs r, write out the entire relocation
- chain to the object file. */
- static void macho_write_relocs (struct reloc *r)
- {
- while (r) {
- uint32_t word2;
- fwriteint32_t(r->addr, ofile); /* reloc offset */
- word2 = r->snum;
- word2 |= r->pcrel << 24;
- word2 |= r->length << 25;
- word2 |= r->ext << 27;
- word2 |= r->type << 28;
- fwriteint32_t(word2, ofile); /* reloc data */
- r = r->next;
- }
- }
- /* Write out the section data. */
- static void macho_write_section (void)
- {
- struct section *s;
- struct reloc *r;
- uint8_t *p;
- int32_t len;
- int64_t l;
- union offset {
- uint64_t val;
- uint8_t buf[8];
- } blk;
- for (s = sects; s != NULL; s = s->next) {
- if ((s->flags & SECTION_TYPE) == S_ZEROFILL)
- continue;
- /* Like a.out Mach-O references things in the data or bss
- * sections by addresses which are actually relative to the
- * start of the _text_ section, in the _file_. See outaout.c
- * for more information. */
- saa_rewind(s->data);
- for (r = s->relocs; r != NULL; r = r->next) {
- len = (uint32_t)1 << r->length;
- if (len > 4) /* Can this ever be an issue?! */
- len = 8;
- blk.val = 0;
- saa_fread(s->data, r->addr, blk.buf, len);
- /* get offset based on relocation type */
- #ifdef WORDS_LITTLEENDIAN
- l = blk.val;
- #else
- l = blk.buf[0];
- l += ((int64_t)blk.buf[1]) << 8;
- l += ((int64_t)blk.buf[2]) << 16;
- l += ((int64_t)blk.buf[3]) << 24;
- l += ((int64_t)blk.buf[4]) << 32;
- l += ((int64_t)blk.buf[5]) << 40;
- l += ((int64_t)blk.buf[6]) << 48;
- l += ((int64_t)blk.buf[7]) << 56;
- #endif
- /* If the relocation is internal add to the current section
- offset. Otherwise the only value we need is the symbol
- offset which we already have. The linker takes care
- of the rest of the address. */
- if (!r->ext) {
- /* generate final address by section address and offset */
- nasm_assert(r->snum <= seg_nsects);
- l += sectstab[r->snum]->addr;
- if (r->pcrel)
- l -= s->addr;
- } else if (r->pcrel && r->type == GENERIC_RELOC_VANILLA) {
- l -= s->addr;
- }
- /* write new offset back */
- p = blk.buf;
- WRITEDLONG(p, l);
- saa_fwrite(s->data, r->addr, blk.buf, len);
- }
- /* dump the section data to file */
- fwritezero(s->pad, ofile);
- saa_fpwrite(s->data, ofile);
- }
- /* pad last section up to reloc entries on pointer boundary */
- fwritezero(rel_padcnt, ofile);
- /* emit relocation entries */
- for (s = sects; s != NULL; s = s->next)
- macho_write_relocs (s->relocs);
- }
- /* Write out the symbol table. We should already have sorted this
- before now. */
- static void macho_write_symtab (void)
- {
- struct symbol *sym;
- uint64_t i;
- /* we don't need to pad here since MACHO_RELINFO_SIZE == 8 */
- for (sym = syms; sym != NULL; sym = sym->next) {
- if ((sym->type & N_EXT) == 0) {
- fwriteint32_t(sym->strx, ofile); /* string table entry number */
- nasm_write(&sym->type, 1, ofile); /* symbol type */
- nasm_write(&sym->sect, 1, ofile); /* section */
- fwriteint16_t(sym->desc, ofile); /* description */
- /* Fix up the symbol value now that we know the final section
- sizes. */
- if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
- nasm_assert(sym->sect <= seg_nsects);
- sym->symv[0].key += sectstab[sym->sect]->addr;
- }
- fwriteptr(sym->symv[0].key, ofile); /* value (i.e. offset) */
- }
- }
- for (i = 0; i < nextdefsym; i++) {
- sym = extdefsyms[i];
- fwriteint32_t(sym->strx, ofile);
- nasm_write(&sym->type, 1, ofile); /* symbol type */
- nasm_write(&sym->sect, 1, ofile); /* section */
- fwriteint16_t(sym->desc, ofile); /* description */
- /* Fix up the symbol value now that we know the final section
- sizes. */
- if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
- nasm_assert(sym->sect <= seg_nsects);
- sym->symv[0].key += sectstab[sym->sect]->addr;
- }
- fwriteptr(sym->symv[0].key, ofile); /* value (i.e. offset) */
- }
- for (i = 0; i < nundefsym; i++) {
- sym = undefsyms[i];
- fwriteint32_t(sym->strx, ofile);
- nasm_write(&sym->type, 1, ofile); /* symbol type */
- nasm_write(&sym->sect, 1, ofile); /* section */
- fwriteint16_t(sym->desc, ofile); /* description */
- /* Fix up the symbol value now that we know the final section
- sizes. */
- if (((sym->type & N_TYPE) == N_SECT) && (sym->sect != NO_SECT)) {
- nasm_assert(sym->sect <= seg_nsects);
- sym->symv[0].key += sectstab[sym->sect]->addr;
- }
- fwriteptr(sym->symv[0].key, ofile); /* value (i.e. offset) */
- }
- }
- /* Fixup the snum in the relocation entries, we should be
- doing this only for externally referenced symbols. */
- static void macho_fixup_relocs (struct reloc *r)
- {
- struct symbol *sym;
- while (r != NULL) {
- if (r->ext) {
- for (sym = syms; sym != NULL; sym = sym->next) {
- if (sym->initial_snum == r->snum) {
- r->snum = sym->snum;
- break;
- }
- }
- }
- r = r->next;
- }
- }
- /* Write out the object file. */
- static void macho_write (void)
- {
- uint64_t offset = 0;
- /* mach-o object file structure:
- **
- ** mach header
- ** uint32_t magic
- ** int cpu type
- ** int cpu subtype
- ** uint32_t mach file type
- ** uint32_t number of load commands
- ** uint32_t size of all load commands
- ** (includes section struct size of segment command)
- ** uint32_t flags
- **
- ** segment command
- ** uint32_t command type == LC_SEGMENT[_64]
- ** uint32_t size of load command
- ** (including section load commands)
- ** char[16] segment name
- ** pointer in-memory offset
- ** pointer in-memory size
- ** pointer in-file offset to data area
- ** pointer in-file size
- ** (in-memory size excluding zerofill sections)
- ** int maximum vm protection
- ** int initial vm protection
- ** uint32_t number of sections
- ** uint32_t flags
- **
- ** section commands
- ** char[16] section name
- ** char[16] segment name
- ** pointer in-memory offset
- ** pointer in-memory size
- ** uint32_t in-file offset
- ** uint32_t alignment
- ** (irrelevant in MH_OBJECT)
- ** uint32_t in-file offset of relocation entires
- ** uint32_t number of relocations
- ** uint32_t flags
- ** uint32_t reserved
- ** uint32_t reserved
- **
- ** symbol table command
- ** uint32_t command type == LC_SYMTAB
- ** uint32_t size of load command
- ** uint32_t symbol table offset
- ** uint32_t number of symbol table entries
- ** uint32_t string table offset
- ** uint32_t string table size
- **
- ** raw section data
- **
- ** padding to pointer boundary
- **
- ** relocation data (struct reloc)
- ** int32_t offset
- ** uint data (symbolnum, pcrel, length, extern, type)
- **
- ** symbol table data (struct nlist)
- ** int32_t string table entry number
- ** uint8_t type
- ** (extern, absolute, defined in section)
- ** uint8_t section
- ** (0 for global symbols, section number of definition (>= 1, <=
- ** 254) for local symbols, size of variable for common symbols
- ** [type == extern])
- ** int16_t description
- ** (for stab debugging format)
- ** pointer value (i.e. file offset) of symbol or stab offset
- **
- ** string table data
- ** list of null-terminated strings
- */
- /* Emit the Mach-O header. */
- macho_write_header();
- offset = fmt.header_size + head_sizeofcmds;
- /* emit the segment load command */
- if (seg_nsects > 0)
- offset = macho_write_segment (offset);
- else
- nasm_error(ERR_WARNING, "no sections?");
- if (nsyms > 0) {
- /* write out symbol command */
- fwriteint32_t(LC_SYMTAB, ofile); /* cmd == LC_SYMTAB */
- fwriteint32_t(MACHO_SYMCMD_SIZE, ofile); /* size of load command */
- fwriteint32_t(offset, ofile); /* symbol table offset */
- fwriteint32_t(nsyms, ofile); /* number of symbol
- ** table entries */
- offset += nsyms * fmt.nlist_size;
- fwriteint32_t(offset, ofile); /* string table offset */
- fwriteint32_t(strslen, ofile); /* string table size */
- }
- /* emit section data */
- if (seg_nsects > 0)
- macho_write_section ();
- /* emit symbol table if we have symbols */
- if (nsyms > 0)
- macho_write_symtab ();
- /* we don't need to pad here, we are already aligned */
- /* emit string table */
- saa_fpwrite(strs, ofile);
- }
- /* We do quite a bit here, starting with finalizing all of the data
- for the object file, writing, and then freeing all of the data from
- the file. */
- static void macho_cleanup(void)
- {
- struct section *s;
- struct reloc *r;
- struct symbol *sym;
- dfmt->cleanup();
- /* Sort all symbols. */
- macho_layout_symbols (&nsyms, &strslen);
- /* Fixup relocation entries */
- for (s = sects; s != NULL; s = s->next) {
- macho_fixup_relocs (s->relocs);
- }
- /* First calculate and finalize needed values. */
- macho_calculate_sizes();
- macho_write();
- /* free up everything */
- while (sects->next) {
- s = sects;
- sects = sects->next;
- saa_free(s->data);
- while (s->relocs != NULL) {
- r = s->relocs;
- s->relocs = s->relocs->next;
- nasm_free(r);
- }
- nasm_free(s);
- }
- saa_free(strs);
- raa_free(extsyms);
- while (syms) {
- sym = syms;
- syms = syms->next;
- nasm_free (sym);
- }
- nasm_free(extdefsyms);
- nasm_free(undefsyms);
- nasm_free(sectstab);
- raa_free_ptr(section_by_index);
- hash_free(§ion_by_name);
- }
- static bool macho_set_section_attribute_by_symbol(const char *label, uint32_t flags)
- {
- struct section *s;
- int32_t nasm_seg;
- int64_t offset;
- if (!lookup_label(label, &nasm_seg, &offset)) {
- nasm_error(ERR_NONFATAL, "unknown symbol `%s' in no_dead_strip", label);
- return false;
- }
- s = get_section_by_index(nasm_seg);
- if (!s) {
- nasm_error(ERR_NONFATAL, "symbol `%s' is external or absolute", label);
- return false;
- }
- s->flags |= flags;
- return true;
- }
- /*
- * Mark a symbol for no dead stripping
- */
- static enum directive_result macho_no_dead_strip(const char *labels)
- {
- char *s, *p, *ep;
- char ec;
- enum directive_result rv = DIRR_ERROR;
- bool real = passn > 1;
- p = s = nasm_strdup(labels);
- while (*p) {
- ep = nasm_skip_identifier(p);
- if (!ep) {
- nasm_error(ERR_NONFATAL, "invalid symbol in NO_DEAD_STRIP");
- goto err;
- }
- ec = *ep;
- if (ec && ec != ',' && !nasm_isspace(ec)) {
- nasm_error(ERR_NONFATAL, "cannot parse contents after symbol");
- goto err;
- }
- *ep = '\0';
- if (real) {
- if (!macho_set_section_attribute_by_symbol(p, S_ATTR_NO_DEAD_STRIP))
- rv = DIRR_ERROR;
- }
- *ep = ec;
- p = nasm_skip_spaces(ep);
- if (*p == ',')
- p = nasm_skip_spaces(++p);
- }
- rv = DIRR_OK;
- err:
- nasm_free(s);
- return rv;
- }
- /*
- * Mach-O pragmas
- */
- static enum directive_result
- macho_pragma(const struct pragma *pragma)
- {
- bool real = passn > 1;
- switch (pragma->opcode) {
- case D_SUBSECTIONS_VIA_SYMBOLS:
- if (*pragma->tail)
- return DIRR_BADPARAM;
- if (real)
- head_flags |= MH_SUBSECTIONS_VIA_SYMBOLS;
- /* Jmp-match optimization conflicts */
- optimizing.flag |= OPTIM_DISABLE_JMP_MATCH;
- return DIRR_OK;
- case D_NO_DEAD_STRIP:
- return macho_no_dead_strip(pragma->tail);
- default:
- return DIRR_UNKNOWN; /* Not a Mach-O directive */
- }
- }
- static const struct pragma_facility macho_pragma_list[] = {
- { "macho", macho_pragma },
- { NULL, macho_pragma } /* Implements macho32/macho64 namespaces */
- };
- static void macho_dbg_generate(void)
- {
- uint8_t *p_buf = NULL, *p_buf_base = NULL;
- size_t saa_len = 0, high_addr = 0, total_len = 0;
- struct section *p_section = NULL;
- /* calculated at debug_str and referenced at debug_info */
- uint32_t producer_str_offset = 0, module_str_offset = 0, dir_str_offset = 0;
- /* debug section defines */
- {
- int bits = 0;
- macho_section(".debug_abbrev", 0, &bits);
- macho_section(".debug_info", 0, &bits);
- macho_section(".debug_line", 0, &bits);
- macho_section(".debug_str", 0, &bits);
- }
- /* dw section walk to find high_addr and total_len */
- {
- struct dw_sect_list *p_sect;
- list_for_each(p_sect, dw_head_sect) {
- uint64_t offset = get_section_by_index(p_sect->section)->size;
- struct SAA *p_linep = p_sect->psaa;
- saa_write8(p_linep, 2); /* std op 2 */
- saa_write8(p_linep, offset - p_sect->offset);
- saa_write8(p_linep, DW_LNS_extended_op);
- saa_write8(p_linep, 1); /* operand length */
- saa_write8(p_linep, DW_LNE_end_sequence);
- total_len += p_linep->datalen;
- high_addr += offset;
- }
- }
- /* debug line */
- {
- struct dw_sect_list *p_sect;
- size_t linep_off, buf_size;
- struct SAA *p_lines = saa_init(1L);
- struct dir_list *p_dir;
- struct file_list *p_file;
- p_section = get_section_by_name("__DWARF", "__debug_line");
- nasm_assert(p_section != NULL);
- saa_write8(p_lines, 1); /* minimum instruction length */
- saa_write8(p_lines, 1); /* initial value of "is_stmt" */
- saa_write8(p_lines, DW_LN_BASE); /* line base */
- saa_write8(p_lines, DW_LN_RANGE); /* line range */
- saa_write8(p_lines, DW_OPCODE_BASE); /* opcode base */
- saa_write8(p_lines, 0); /* std opcode 1 length */
- saa_write8(p_lines, 1); /* std opcode 2 length */
- saa_write8(p_lines, 1); /* std opcode 3 length */
- saa_write8(p_lines, 1); /* std opcode 4 length */
- saa_write8(p_lines, 1); /* std opcode 5 length */
- saa_write8(p_lines, 0); /* std opcode 6 length */
- saa_write8(p_lines, 0); /* std opcode 7 length */
- saa_write8(p_lines, 0); /* std opcode 8 length */
- saa_write8(p_lines, 1); /* std opcode 9 length */
- saa_write8(p_lines, 0); /* std opcode 10 length */
- saa_write8(p_lines, 0); /* std opcode 11 length */
- saa_write8(p_lines, 1); /* std opcode 12 length */
- list_for_each(p_dir, dw_head_dir) {
- saa_wcstring(p_lines, p_dir->dir_name);
- }
- saa_write8(p_lines, 0); /* end of table */
- list_for_each(p_file, dw_head_file) {
- saa_wcstring(p_lines, p_file->file_name);
- saa_write8(p_lines, p_file->dir->dir); /* directory id */
- saa_write8(p_lines, 0); /* time */
- saa_write8(p_lines, 0); /* size */
- }
- saa_write8(p_lines, 0); /* end of table */
- linep_off = p_lines->datalen;
- /* 10 bytes for initial & prolong length, and dwarf version info */
- buf_size = saa_len = linep_off + total_len + 10;
- p_buf_base = p_buf = nasm_malloc(buf_size);
- WRITELONG(p_buf, saa_len - 4); /* initial length; size excluding itself */
- WRITESHORT(p_buf, 2); /* dwarf version */
- WRITELONG(p_buf, linep_off); /* prolong length */
- saa_rnbytes(p_lines, p_buf, linep_off);
- p_buf += linep_off;
- saa_free(p_lines);
- list_for_each(p_sect, dw_head_sect) {
- struct SAA *p_linep = p_sect->psaa;
- saa_len = p_linep->datalen;
- saa_rnbytes(p_linep, p_buf, saa_len);
- p_buf += saa_len;
- saa_free(p_linep);
- }
- macho_output(p_section->index, p_buf_base, OUT_RAWDATA, buf_size, NO_SEG, 0);
- nasm_free(p_buf_base);
- }
- /* string section */
- {
- struct SAA *p_str = saa_init(1L);
- char *cur_path = nasm_realpath(module_name);
- char *cur_file = nasm_basename(cur_path);
- char *cur_dir = nasm_dirname(cur_path);
- p_section = get_section_by_name("__DWARF", "__debug_str");
- nasm_assert(p_section != NULL);
- producer_str_offset = 0;
- module_str_offset = dir_str_offset = saa_wcstring(p_str, nasm_signature);
- dir_str_offset += saa_wcstring(p_str, cur_file);
- saa_wcstring(p_str, cur_dir);
- saa_len = p_str->datalen;
- p_buf = nasm_malloc(saa_len);
- saa_rnbytes(p_str, p_buf, saa_len);
- macho_output(p_section->index, p_buf, OUT_RAWDATA, saa_len, NO_SEG, 0);
- nasm_free(cur_path);
- nasm_free(cur_file);
- nasm_free(cur_dir);
- saa_free(p_str);
- nasm_free(p_buf);
- }
- /* debug info */
- {
- struct SAA *p_info = saa_init(1L);
- p_section = get_section_by_name("__DWARF", "__debug_info");
- nasm_assert(p_section != NULL);
- /* size will be overwritten once determined, so skip in p_info layout */
- saa_write16(p_info, 2); /* dwarf version */
- saa_write32(p_info, 0); /* offset info abbrev */
- saa_write8(p_info, (ofmt == &of_macho64) ? 8 : 4); /* pointer size */
- saa_write8(p_info, 1); /* abbrev entry number */
- saa_write32(p_info, producer_str_offset); /* offset from string table for DW_AT_producer */
- saa_write16(p_info, DW_LANG_Mips_Assembler); /* DW_AT_language */
- saa_write32(p_info, module_str_offset); /* offset from string table for DW_AT_name */
- saa_write32(p_info, dir_str_offset); /* offset from string table for DW_AT_comp_dir */
- saa_write32(p_info, 0); /* DW_AT_stmt_list */
- if (ofmt == &of_macho64) {
- saa_write64(p_info, 0); /* DW_AT_low_pc */
- saa_write64(p_info, high_addr); /* DW_AT_high_pc */
- } else {
- saa_write32(p_info, 0); /* DW_AT_low_pc */
- saa_write32(p_info, high_addr); /* DW_AT_high_pc */
- }
- saa_write8(p_info, 2); /* abbrev entry number */
- if (ofmt == &of_macho64) {
- saa_write64(p_info, 0); /* DW_AT_low_pc */
- saa_write64(p_info, 0); /* DW_AT_frame_base */
- } else {
- saa_write32(p_info, 0); /* DW_AT_low_pc */
- saa_write32(p_info, 0); /* DW_AT_frame_base */
- }
- saa_write8(p_info, DW_END_default);
- saa_len = p_info->datalen;
- p_buf_base = p_buf = nasm_malloc(saa_len + 4); /* 4B for size info */
- WRITELONG(p_buf, saa_len);
- saa_rnbytes(p_info, p_buf, saa_len);
- macho_output(p_section->index, p_buf_base, OUT_RAWDATA, saa_len + 4, NO_SEG, 0);
- saa_free(p_info);
- nasm_free(p_buf_base);
- }
- /* abbrev section */
- {
- struct SAA *p_abbrev = saa_init(1L);
- p_section = get_section_by_name("__DWARF", "__debug_abbrev");
- nasm_assert(p_section != NULL);
- saa_write8(p_abbrev, 1); /* entry number */
- saa_write8(p_abbrev, DW_TAG_compile_unit);
- saa_write8(p_abbrev, DW_CHILDREN_yes);
- saa_write8(p_abbrev, DW_AT_producer);
- saa_write8(p_abbrev, DW_FORM_strp);
- saa_write8(p_abbrev, DW_AT_language);
- saa_write8(p_abbrev, DW_FORM_data2);
- saa_write8(p_abbrev, DW_AT_name);
- saa_write8(p_abbrev, DW_FORM_strp);
- saa_write8(p_abbrev, DW_AT_comp_dir);
- saa_write8(p_abbrev, DW_FORM_strp);
- saa_write8(p_abbrev, DW_AT_stmt_list);
- saa_write8(p_abbrev, DW_FORM_data4);
- saa_write8(p_abbrev, DW_AT_low_pc);
- saa_write8(p_abbrev, DW_FORM_addr);
- saa_write8(p_abbrev, DW_AT_high_pc);
- saa_write8(p_abbrev, DW_FORM_addr);
- saa_write16(p_abbrev, DW_END_default);
- saa_write8(p_abbrev, 2); /* entry number */
- saa_write8(p_abbrev, DW_TAG_subprogram);
- saa_write8(p_abbrev, DW_CHILDREN_no);
- saa_write8(p_abbrev, DW_AT_low_pc);
- saa_write8(p_abbrev, DW_FORM_addr);
- saa_write8(p_abbrev, DW_AT_frame_base);
- saa_write8(p_abbrev, DW_FORM_addr);
- saa_write16(p_abbrev, DW_END_default);
- saa_write8(p_abbrev, 0); /* Terminal zero entry */
- saa_len = p_abbrev->datalen;
- p_buf = nasm_malloc(saa_len);
- saa_rnbytes(p_abbrev, p_buf, saa_len);
- macho_output(p_section->index, p_buf, OUT_RAWDATA, saa_len, NO_SEG, 0);
- saa_free(p_abbrev);
- nasm_free(p_buf);
- }
- }
- static void new_file_list (const char *file_name, const char *dir_name)
- {
- struct dir_list *dir_list;
- bool need_new_dir_list = true;
- nasm_new(dw_cur_file);
- dw_cur_file->file = ++dw_num_files;
- dw_cur_file->file_name = file_name;
- if(!dw_head_file) {
- dw_head_file = dw_cur_file;
- } else {
- *dw_last_file_next = dw_cur_file;
- }
- dw_last_file_next = &(dw_cur_file->next);
- if(dw_head_dir) {
- list_for_each(dir_list, dw_head_dir) {
- if(!(strcmp(dir_name, dir_list->dir_name))) {
- dw_cur_file->dir = dir_list;
- need_new_dir_list = false;
- break;
- }
- }
- }
- if(need_new_dir_list)
- {
- nasm_new(dir_list);
- dir_list->dir = dw_num_dirs++;
- dir_list->dir_name = dir_name;
- if(!dw_head_dir) {
- dw_head_dir = dir_list;
- } else {
- *dw_last_dir_next = dir_list;
- }
- dw_last_dir_next = &(dir_list->next);
- dw_cur_file->dir = dir_list;
- }
- }
- static void macho_dbg_init(void)
- {
- }
- static void macho_dbg_linenum(const char *file_name, int32_t line_num, int32_t segto)
- {
- bool need_new_list = true;
- const char *cur_file = nasm_basename(file_name);
- const char *cur_dir = nasm_dirname(file_name);
- (void)segto;
- if(!dw_cur_file || strcmp(cur_file, dw_cur_file->file_name) ||
- strcmp(cur_dir, dw_cur_file->dir->dir_name)) {
- if(dw_head_file) {
- struct file_list *match;
- list_for_each(match, dw_head_file) {
- if(!(strcmp(cur_file, match->file_name)) &&
- !(strcmp(cur_dir, match->dir->dir_name))) {
- dw_cur_file = match;
- dw_cur_file->dir = match->dir;
- need_new_list = false;
- break;
- }
- }
- }
- if(need_new_list) {
- new_file_list(cur_file, cur_dir);
- }
- }
- dbg_immcall = true;
- cur_line = line_num;
- }
- static void macho_dbg_output(int type, void *param)
- {
- struct section_info *sinfo_param = (struct section_info *)param;
- int32_t secto = sinfo_param->secto;
- bool need_new_sect = false;
- struct SAA *p_linep = NULL;
- (void)type;
- if(!(dw_cur_sect && (dw_cur_sect->section == secto))) {
- need_new_sect = true;
- if(dw_head_sect) {
- struct dw_sect_list *match = dw_head_sect;
- uint32_t idx = 0;
- for(; idx < dw_num_sects; idx++) {
- if(match->section == secto) {
- dw_cur_sect = match;
- need_new_sect = false;
- break;
- }
- match = match->next;
- }
- }
- }
- if(need_new_sect) {
- nasm_new(dw_cur_sect);
- dw_num_sects ++;
- p_linep = dw_cur_sect->psaa = saa_init(1L);
- dw_cur_sect->line = dw_cur_sect->file = 1;
- dw_cur_sect->offset = 0;
- dw_cur_sect->next = NULL;
- dw_cur_sect->section = secto;
- saa_write8(p_linep, DW_LNS_extended_op);
- saa_write8(p_linep, (ofmt == &of_macho64) ? 9 : 5);
- saa_write8(p_linep, DW_LNE_set_address);
- if (ofmt == &of_macho64) {
- saa_write64(p_linep, 0);
- } else {
- saa_write32(p_linep, 0);
- }
- if(!dw_head_sect) {
- dw_head_sect = dw_last_sect = dw_cur_sect;
- } else {
- dw_last_sect->next = dw_cur_sect;
- dw_last_sect = dw_cur_sect;
- }
- }
- if(dbg_immcall == true) {
- int32_t line_delta = cur_line - dw_cur_sect->line;
- int32_t offset_delta = sinfo_param->size - dw_cur_sect->offset;
- uint32_t cur_file = dw_cur_file->file;
- p_linep = dw_cur_sect->psaa;
- if(cur_file != dw_cur_sect->file) {
- saa_write8(p_linep, DW_LNS_set_file);
- saa_write8(p_linep, cur_file);
- dw_cur_sect->file = cur_file;
- }
- if(line_delta) {
- int special_opcode = (line_delta - DW_LN_BASE) + (DW_LN_RANGE * offset_delta) +
- DW_OPCODE_BASE;
- if((line_delta >= DW_LN_BASE) && (line_delta < DW_MAX_LN) &&
- (special_opcode < DW_MAX_SP_OPCODE)) {
- saa_write8(p_linep, special_opcode);
- } else {
- saa_write8(p_linep, DW_LNS_advance_line);
- saa_wleb128s(p_linep, line_delta);
- if(offset_delta) {
- saa_write8(p_linep, DW_LNS_advance_pc);
- saa_wleb128u(p_linep, offset_delta);
- }
- saa_write8(p_linep, DW_LNS_copy);
- }
- dw_cur_sect->line = cur_line;
- dw_cur_sect->offset = sinfo_param->size;
- }
- dbg_immcall = false;
- }
- }
- static void macho_dbg_cleanup(void)
- {
- /* dwarf sectors generation */
- macho_dbg_generate();
- {
- struct dw_sect_list *p_sect = dw_head_sect;
- struct file_list *p_file = dw_head_file;
- uint32_t idx = 0;
- for(; idx < dw_num_sects; idx++) {
- struct dw_sect_list *next = p_sect->next;
- nasm_free(p_sect);
- p_sect = next;
- }
- for(idx = 0; idx < dw_num_files; idx++) {
- struct file_list *next = p_file->next;
- nasm_free(p_file);
- p_file = next;
- }
- }
- }
- #ifdef OF_MACHO32
- static const struct macho_fmt macho32_fmt = {
- 4,
- MH_MAGIC,
- CPU_TYPE_I386,
- LC_SEGMENT,
- MACHO_HEADER_SIZE,
- MACHO_SEGCMD_SIZE,
- MACHO_SECTCMD_SIZE,
- MACHO_NLIST_SIZE,
- RL_MAX_32,
- GENERIC_RELOC_VANILLA,
- GENERIC_RELOC_VANILLA,
- GENERIC_RELOC_TLV,
- false /* Allow segment-relative relocations */
- };
- static void macho32_init(void)
- {
- fmt = macho32_fmt;
- macho_init();
- macho_gotpcrel_sect = NO_SEG;
- }
- static const struct dfmt macho32_df_dwarf = {
- "MachO32 (i386) dwarf debug format for Darwin/MacOS",
- "dwarf",
- macho_dbg_init,
- macho_dbg_linenum,
- null_debug_deflabel,
- null_debug_directive,
- null_debug_typevalue,
- macho_dbg_output,
- macho_dbg_cleanup,
- NULL /*pragma list*/
- };
- static const struct dfmt * const macho32_df_arr[2] =
- { &macho32_df_dwarf, NULL };
- const struct ofmt of_macho32 = {
- "NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (i386) object files",
- "macho32",
- ".o",
- 0,
- 32,
- macho32_df_arr,
- &macho32_df_dwarf,
- macho_stdmac,
- macho32_init,
- null_reset,
- nasm_do_legacy_output,
- macho_output,
- macho_symdef,
- macho_section,
- macho_herelabel,
- macho_sectalign,
- macho_segbase,
- null_directive,
- macho_cleanup,
- macho_pragma_list
- };
- #endif
- #ifdef OF_MACHO64
- static const struct macho_fmt macho64_fmt = {
- 8,
- MH_MAGIC_64,
- CPU_TYPE_X86_64,
- LC_SEGMENT_64,
- MACHO_HEADER64_SIZE,
- MACHO_SEGCMD64_SIZE,
- MACHO_SECTCMD64_SIZE,
- MACHO_NLIST64_SIZE,
- RL_MAX_64,
- X86_64_RELOC_UNSIGNED,
- X86_64_RELOC_SIGNED,
- X86_64_RELOC_TLV,
- true /* Force symbol-relative relocations */
- };
- static void macho64_init(void)
- {
- fmt = macho64_fmt;
- macho_init();
- /* add special symbol for ..gotpcrel */
- macho_gotpcrel_sect = seg_alloc() + 1;
- backend_label("..gotpcrel", macho_gotpcrel_sect, 0L);
- }
- static const struct dfmt macho64_df_dwarf = {
- "MachO64 (x86-64) dwarf debug format for Darwin/MacOS",
- "dwarf",
- macho_dbg_init,
- macho_dbg_linenum,
- null_debug_deflabel,
- null_debug_directive,
- null_debug_typevalue,
- macho_dbg_output,
- macho_dbg_cleanup,
- NULL /*pragma list*/
- };
- static const struct dfmt * const macho64_df_arr[2] =
- { &macho64_df_dwarf, NULL };
- const struct ofmt of_macho64 = {
- "NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X (x86_64) object files",
- "macho64",
- ".o",
- 0,
- 64,
- macho64_df_arr,
- &macho64_df_dwarf,
- macho_stdmac,
- macho64_init,
- null_reset,
- nasm_do_legacy_output,
- macho_output,
- macho_symdef,
- macho_section,
- macho_herelabel,
- macho_sectalign,
- macho_segbase,
- null_directive,
- macho_cleanup,
- macho_pragma_list,
- };
- #endif
- #endif
- /*
- * Local Variables:
- * mode:c
- * c-basic-offset:4
- * End:
- *
- * end of file */
|