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

📄 labels.c

📁 汇编编译器的最新版本的源码.买了自己动手写操作系统这本书的人一定要下
💻 C
📖 第 1 页 / 共 2 页
字号:
/* labels.c  label handling for the Netwide Assembler
 *
 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
 * Julian Hall. All rights reserved. The software is
 * redistributable under the license given in the file "LICENSE"
 * distributed in the NASM archive.
 */

#include "compiler.h"

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

#include "nasm.h"
#include "nasmlib.h"
#include "hashtbl.h"

/*
 * A local label is one that begins with exactly one period. Things
 * that begin with _two_ periods are NASM-specific things.
 *
 * If TASM compatibility is enabled, a local label can also begin with
 * @@, so @@local is a TASM compatible local label. Note that we only
 * check for the first @ symbol, although TASM requires both.
 */
#define islocal(l)                                              \
	(tasm_compatible_mode ?					\
	(((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') :   \
	((l)[0] == '.' && (l)[1] != '.'))
#define islocalchar(c)						\
	(tasm_compatible_mode ?                                  \
	((c) == '.' || (c) == '@') :                            \
	((c) == '.'))

#define LABEL_BLOCK  128	/* no. of labels/block */
#define LBLK_SIZE    (LABEL_BLOCK*sizeof(union label))

#define END_LIST -3             /* don't clash with NO_SEG! */
#define END_BLOCK -2
#define BOGUS_VALUE -4

#define PERMTS_SIZE  4096       /* size of text blocks */
#if (PERMTS_SIZE > IDLEN_MAX)
#error "IPERMTS_SIZE must be less than or equal to IDLEN_MAX"
#endif

/* values for label.defn.is_global */
#define DEFINED_BIT 1
#define GLOBAL_BIT 2
#define EXTERN_BIT 4

#define NOT_DEFINED_YET 0
#define TYPE_MASK 3
#define LOCAL_SYMBOL (DEFINED_BIT)
#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)

union label {                   /* actual label structures */
    struct {
        int32_t segment;
	int64_t offset;
        char *label, *special;
        int is_global, is_norm;
    } defn;
    struct {
        int32_t movingon;
        int64_t dummy;
        union label *next;
    } admin;
};

struct permts {                 /* permanent text storage */
    struct permts *next;        /* for the linked list */
    int size, usage;            /* size and used space in ... */
    char data[PERMTS_SIZE];     /* ... the data block itself */
};

extern int64_t global_offset_changed;       /* defined in nasm.c */

static struct hash_table ltab;		/* labels hash table */
static union label *ldata;		/* all label data blocks */
static union label *lfree;		/* labels free block */
static struct permts *perm_head;        /* start of perm. text storage */
static struct permts *perm_tail;        /* end of perm. text storage */

static void init_block(union label *blk);
static char *perm_copy(const char *string);

static char *prevlabel;

static bool initialized = false;

char lprefix[PREFIX_MAX] = { 0 };
char lpostfix[PREFIX_MAX] = { 0 };

/*
 * Internal routine: finds the `union label' corresponding to the
 * given label name. Creates a new one, if it isn't found, and if
 * `create' is true.
 */
static union label *find_label(char *label, int create)
{
    char *prev;
    int prevlen, len;
    union label *lptr, **lpp;
    char label_str[IDLEN_MAX];
    struct hash_insert ip;

    if (islocal(label)) {
        prev = prevlabel;
	prevlen = strlen(prev);
	len = strlen(label);
	if (prevlen+len >= IDLEN_MAX)
	    return NULL;	/* Error... */
	memcpy(label_str, prev, prevlen);
	memcpy(label_str+prevlen, label, len+1);
	label = label_str;
    } else {
        prev = "";
	prevlen = 0;
    }

    lpp = (union label **) hash_find(&ltab, label, &ip);
    lptr = lpp ? *lpp : NULL;

    if (lptr || !create)
	return lptr;

    /* Create a new label... */
    if (lfree->admin.movingon == END_BLOCK) {
	/*
	 * must allocate a new block
	 */
	lfree->admin.next =
	    (union label *)nasm_malloc(LBLK_SIZE);
	lfree = lfree->admin.next;
	init_block(lfree);
    }

    lfree->admin.movingon = BOGUS_VALUE;
    lfree->defn.label = perm_copy(label);
    lfree->defn.special = NULL;
    lfree->defn.is_global = NOT_DEFINED_YET;

    hash_add(&ip, lfree->defn.label, lfree);
    return lfree++;
}

bool lookup_label(char *label, int32_t *segment, int64_t *offset)
{
    union label *lptr;

    if (!initialized)
        return false;

    lptr = find_label(label, 0);
    if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
        *segment = lptr->defn.segment;
        *offset = lptr->defn.offset;
        return true;
    } else
        return false;
}

bool is_extern(char *label)
{
    union label *lptr;

    if (!initialized)
        return false;

    lptr = find_label(label, 0);
    return (lptr && (lptr->defn.is_global & EXTERN_BIT));
}

void redefine_label(char *label, int32_t segment, int64_t offset, char *special,
                    bool is_norm, bool isextrn, struct ofmt *ofmt,
                    efunc error)
{
    union label *lptr;
    int exi;

    /* This routine possibly ought to check for phase errors.  Most assemblers
     * check for phase errors at this point.  I don't know whether phase errors
     * are even possible, nor whether they are checked somewhere else
     */

    (void)special;              /* Don't warn that this parameter is unused */
    (void)is_norm;              /* Don't warn that this parameter is unused */
    (void)isextrn;              /* Don't warn that this parameter is unused */
    (void)ofmt;                 /* Don't warn that this parameter is unused */

#ifdef DEBUG
#if DEBUG<3
    if (!strncmp(label, "debugdump", 9))
#endif
        error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
              label, segment, offset, special, is_norm, isextrn);
#endif

    lptr = find_label(label, 1);
    if (!lptr)
        error(ERR_PANIC, "can't find label `%s' on pass two", label);

    if (!islocal(label)) {
        if (!islocalchar(*label) && lptr->defn.is_norm)
            prevlabel = lptr->defn.label;
    }

    if (lptr->defn.offset != offset) global_offset_changed++;
    lptr->defn.offset = offset;
    lptr->defn.segment = segment;

    if (pass0 == 1) {
        exi = !!(lptr->defn.is_global & GLOBAL_BIT);
        if (exi) {
            char *xsymbol;
            int slen;
            slen = strlen(lprefix);
            slen += strlen(lptr->defn.label);
            slen += strlen(lpostfix);
            slen++;             /* room for that null char */
            xsymbol = nasm_malloc(slen);
            snprintf(xsymbol, slen, "%s%s%s", lprefix, lptr->defn.label,
                     lpostfix);

            ofmt->symdef(xsymbol, segment, offset, exi,
                         special ? special : lptr->defn.special);
            ofmt->current_dfmt->debug_deflabel(xsymbol, segment, offset,
                                               exi,
                                               special ? special : lptr->
                                               defn.special);
/**	nasm_free(xsymbol);  ! outobj.c stores the pointer; ouch!!! **/
        } else {
            if ((lptr->defn.is_global & (GLOBAL_BIT | EXTERN_BIT)) !=
                EXTERN_BIT) {
                ofmt->symdef(lptr->defn.label, segment, offset, exi,
                             special ? special : lptr->defn.special);
                ofmt->current_dfmt->debug_deflabel(label, segment, offset,
                                                   exi,
                                                   special ? special :
                                                   lptr->defn.special);

⌨️ 快捷键说明

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