⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 outmacho.c

📁 nasm早期的源代码,比较简单是学习汇编和编译原理的好例子
💻 C
📖 第 1 页 / 共 3 页
字号:
/* outmacho.c	output routines for the Netwide Assembler to produce
 *		NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files
 *
 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
 * Julian Hall. All rights reserved. The software is
 * redistributable under the licence given in the file "Licence"
 * distributed in the NASM archive.
 */

/* Most of this file is, like Mach-O itself, based on a.out. For more
 * guidelines see outaout.c.  */

#include "compiler.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>

#include "nasm.h"
#include "nasmlib.h"
#include "outform.h"
#include "compiler.h"

#if defined(OF_MACHO)

/* 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)

/* Mach-O file header values */
#define	MH_MAGIC		(0xfeedface)
#define CPU_TYPE_I386		(7)     /* x86 platform */
#define	CPU_SUBTYPE_I386_ALL	(3)     /* all-x86 compatible */
#define	MH_OBJECT		(0x1)   /* object file */

#define	LC_SEGMENT		(0x1)   /* segment load command */
#define LC_SYMTAB		(0x2)   /* symbol table load command */

#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)

struct section {
    /* nasm internal data */
    struct section *next;
    struct SAA *data;
    int32_t index;
    struct reloc *relocs;
    int align;

    /* data that goes into the file */
    char sectname[16];          /* what this section is called */
    char segname[16];           /* segment this section will be in */
    uint32_t size;         /* in-memory and -file size  */
    uint32_t nreloc;       /* relocation entry count */
    uint32_t flags;        /* type and attributes (masked) */
};

#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 */


static struct sectmap {
    const char *nasmsect;
    const char *segname;
    const char *sectname;
    const int32_t flags;
} sectmap[] = {
    {".text", "__TEXT", "__text", S_REGULAR|S_ATTR_SOME_INSTRUCTIONS},
    {".data", "__DATA", "__data", S_REGULAR},
    {".rodata", "__DATA", "__const", S_REGULAR},
    {".bss", "__DATA", "__bss", S_ZEROFILL},
    {NULL, NULL, NULL, 0}
};

struct reloc {
    /* nasm internal data */
    struct reloc *next;

    /* data that goes into the file */
    int32_t addr;                  /* op's offset in section */
    unsigned int 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 */
	ext:1,                  /* external symbol referenced */
	type:4;                 /* reloc type, 0 for us */
};

#define	R_ABS		0       /* absolute relocation */
#define R_SCATTERED	0x80000000      /* reloc entry is scattered if
					** highest bit == 1 */

struct symbol {
    /* nasm internal data */
    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 */
    int32_t strx;                  /* string table index */
    uint8_t type;         /* symbol type */
    uint8_t sect;         /* NO_SECT or section number */
    int16_t desc;                 /* for stab debugging, 0 for us */
    uint32_t value;        /* offset of symbol in section */
};

/* symbol type bits */
#define	N_EXT	0x01            /* global or 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;
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;

static FILE *machofp;
static efunc error;
static evalfunc evaluate;

extern struct ofmt of_macho;

/* Global file information. This should be cleaned up into either
   a structure or as function arguments.  */
uint32_t head_ncmds = 0;
uint32_t head_sizeofcmds = 0;
uint32_t seg_filesize = 0;
uint32_t seg_vmsize = 0;
uint32_t seg_nsects = 0;
uint32_t rel_padcnt = 0;


#define xstrncpy(xdst, xsrc)						\
    memset(xdst, '\0', sizeof(xdst));	/* zero out whole buffer */	\
    strncpy(xdst, xsrc, sizeof(xdst));	/* copy over string */		\
    xdst[sizeof(xdst) - 1] = '\0';      /* proper null-termination */

#define align(x, y)							\
    (((x) + (y) - 1) & ~((y) - 1))      /* align x to multiple of y */

#define alignint32_t(x)							\
    align(x, sizeof(int32_t))      /* align x to int32_t boundary */

static void debug_reloc (struct reloc *);
static void debug_section_relocs (struct section *) _unused;

static int exact_log2 (uint32_t align)
{
    if (align == 0) {
	return 0;
    } else if (align & (align-1)) {
	return -1;		/* Not a power of 2 */
    } else {
#ifdef HAVE_GNUC_4
	return __builtin_ctzl (align);
#else
	uint32_t result = 0;

	/* We know exactly one bit is set at this point. */
	if (align & 0xffff0000)
	    result |= 16;
	if (align & 0xff00ff00)
	    result |= 8;
	if (align & 0xf0f0f0f0)
	    result |= 4;
	if (align & 0xcccccccc)
	    result |= 2;
	if (align & 0xaaaaaaaa)
	    result |= 1;

	return result;
#endif
    }
}

static struct section *get_section_by_name(const char *segname,
                                           const char *sectname)
{
    struct section *s;

    for (s = sects; s != NULL; s = s->next)
        if (!strcmp(s->segname, segname) && !strcmp(s->sectname, sectname))
            break;

    return s;
}

static struct section *get_section_by_index(const int32_t index)
{
    struct section *s;

    for (s = sects; s != NULL; s = s->next)
        if (index == s->index)
            break;

    return s;
}

static int32_t get_section_index_by_name(const char *segname,
                                      const char *sectname)
{
    struct section *s;

    for (s = sects; s != NULL; s = s->next)
        if (!strcmp(s->segname, segname) && !strcmp(s->sectname, sectname))
            return s->index;

    return -1;
}

static char *get_section_name_by_index(const int32_t index)
{
    struct section *s;

    for (s = sects; s != NULL; s = s->next)
        if (index == s->index)
            return s->sectname;

    return NULL;
}

static uint8_t get_section_fileindex_by_index(const int32_t index)
{
    struct section *s;
    uint8_t i = 1;

    for (s = sects; s != NULL && i < MAX_SECT; s = s->next, ++i)
        if (index == s->index)
            return i;

    if (i == MAX_SECT)
        error(ERR_WARNING,
              "too many sections (>255) - clipped by fileindex");

    return NO_SECT;
}

static void macho_init(FILE * fp, efunc errfunc, ldfunc ldef,
                       evalfunc eval)
{
    char zero = 0;

    machofp = fp;
    error = errfunc;
    evaluate = eval;

    (void)ldef;                 /* placate optimisers */

    sects = NULL;
    sectstail = &sects;

    syms = NULL;
    symstail = &syms;
    nsyms = 0;
    nlocalsym = 0;
    nextdefsym = 0;
    nundefsym = 0;

    extsyms = raa_init();
    strs = saa_init(1L);

    /* string table starts with a zero byte - don't ask why */
    saa_wbytes(strs, &zero, sizeof(char));
    strslen = 1;
}

static int macho_setinfo(enum geninfo type, char **val)
{
    (void)type;
    (void)val;
    return 0;
}

static void sect_write(struct section *sect,
                       const uint8_t *data, uint32_t len)
{
    saa_wbytes(sect->data, data, len);
    sect->size += len;
}

static void add_reloc(struct section *sect, int32_t section,
                      int pcrel, int bytes)
{
    struct reloc *r;
    int32_t fi;

    /* 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 = nasm_malloc(sizeof(struct reloc));
    r->next = sect->relocs;
    sect->relocs = r;

    /* 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->addr = sect->size & ~R_SCATTERED;
    r->ext = 0;
    r->pcrel = pcrel;

    /* match byte count 1, 2, 4 to length codes 0, 1, 2 respectively */
    r->length = bytes >> 1;

    /* vanilla relocation (GENERIC_RELOC_VANILLA) */
    r->type = 0;

    if (section == NO_SEG) {
        /* absolute local symbol if no section index given */
        r->snum = R_ABS;
    } else {
        fi = get_section_fileindex_by_index(section);

        if (fi == NO_SECT) {
            /* external symbol if no section with that index known,
             ** symbol number was saved in macho_symdef() */
            r->snum = raa_read(extsyms, section);
            r->ext = 1;
        } else {
            /* local symbol in section fi */
            r->snum = fi;
        }
    }

    ++sect->nreloc;
}

static void macho_output(int32_t secto, const void *data, uint32_t type,
                         int32_t section, int32_t wrt)
{
    struct section *s, *sbss;
    int32_t realbytes = type & OUT_SIZMASK;
    int32_t addr;
    uint8_t mydata[4], *p;

    type &= OUT_TYPMASK;

    if (wrt != NO_SEG) {
        wrt = NO_SEG;
        error(ERR_NONFATAL, "WRT not supported by Mach-O output format");
        /* continue to do _something_ */
    }

    if (secto == NO_SEG) {
        if (type != OUT_RESERVE)
            error(ERR_NONFATAL, "attempt to assemble code in "
                  "[ABSOLUTE] space");

        return;
    }

    s = get_section_by_index(secto);

    if (s == NULL) {
        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 == NULL)
            error(ERR_PANIC, "text section not found");
    }

    sbss = get_section_by_name("__DATA", "__bss");

    if (s == sbss && type != OUT_RESERVE) {
        error(ERR_WARNING, "attempt to initialize memory in the"
              " BSS section: ignored");

        switch (type) {
        case OUT_REL2ADR:
            realbytes = 2;
            break;

        case OUT_REL4ADR:
            realbytes = 4;
            break;

        default:
            break;
        }

        s->size += realbytes;
        return;
    }

    switch (type) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -