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

📄 outelf64.c

📁 汇编编译器的最新版本的源码.买了自己动手写操作系统这本书的人一定要下
💻 C
📖 第 1 页 / 共 5 页
字号:
 * complicated kinds. In shared-library writing, some relocations
 * with respect to global symbols must refer to the precise symbol
 * rather than referring to an offset from the base of the section
 * _containing_ the symbol. Such relocations call to this routine,
 * which searches the symbol list for the symbol in question.
 *
 * R_386_GOT32 references require the _exact_ symbol address to be
 * used; R_386_32 references can be at an offset from the symbol.
 * The boolean argument `exact' tells us this.
 *
 * Return value is the adjusted value of `addr', having become an
 * offset from the symbol rather than the section. Should always be
 * zero when returning from an exact call.
 *
 * Limitation: if you define two symbols at the same place,
 * confusion will occur.
 *
 * Inefficiency: we search, currently, using a linked list which
 * isn't even necessarily sorted.
 */
static void elf_add_gsym_reloc(struct Section *sect,
                               int32_t segment, int64_t offset, int64_t pcrel,
			       int type, bool exact)
{
    struct Reloc *r;
    struct Section *s;
    struct Symbol *sym, *sm;
    int i;

    /*
     * First look up the segment/offset pair and find a global
     * symbol corresponding to it. If it's not one of our segments,
     * then it must be an external symbol, in which case we're fine
     * doing a normal elf_add_reloc after first sanity-checking
     * that the offset from the symbol is zero.
     */
    s = NULL;
    for (i = 0; i < nsects; i++)
        if (segment == sects[i]->index) {
            s = sects[i];
            break;
        }

    if (!s) {
	if (exact && offset)
	    error(ERR_NONFATAL, "invalid access to an external symbol");
	else 
	    elf_add_reloc(sect, segment, offset - pcrel, type);
	return;
    }

    if (exact) {
        /*
         * Find a symbol pointing _exactly_ at this one.
         */
        for (sym = s->gsyms; sym; sym = sym->next)
            if (sym->value == offset)
                break;
	if (!sym) {
	    error(ERR_NONFATAL, "unable to find a suitable global symbol"
		  " for this reference");
	    return;
	}
    } else {
        /*
         * Find the nearest symbol below this one.
         */
        sym = NULL;
        for (sm = s->gsyms; sm; sm = sm->next)
            if (sm->value <= offset && (!sym || sm->value > sym->value))
                sym = sm;
    }

    r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
    sect->tail = &r->next;
    r->next = NULL;

    r->address = sect->len;
    r->offset = offset - pcrel - sym->value;
    r->symbol = GLOBAL_TEMP_BASE + sym->globnum;
    r->type = type;

    sect->nrelocs++;
}

static void elf_out(int32_t segto, const void *data,
		    enum out_type type, uint64_t size,
                    int32_t segment, int32_t wrt)
{
    struct Section *s;
    int64_t addr, zero;
    int i;
    static struct symlininfo sinfo;

    zero = 0;

#if defined(DEBUG) && DEBUG>2
    if (data) fprintf(stderr,
            " elf_out line: %d type: %x seg: %d segto: %d bytes: %x data: %"PRIx64"\n",
               currentline, type, segment, segto, size, *(int64_t *)data);
    else fprintf(stderr,
            " elf_out line: %d type: %x seg: %d segto: %d bytes: %x\n",
               currentline, type, segment, segto, size);
#endif

    /*
     * handle absolute-assembly (structure definitions)
     */
    if (segto == NO_SEG) {
        if (type != OUT_RESERVE)
            error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
                  " space");
        return;
    }

    s = NULL;
    for (i = 0; i < nsects; i++)
        if (segto == sects[i]->index) {
            s = sects[i];
            break;
        }
    if (!s) {
        int tempint;            /* ignored */
        if (segto != elf_section_names(".text", 2, &tempint))
            error(ERR_PANIC, "strange segment conditions in ELF driver");
        else {
            s = sects[nsects - 1];
            i = nsects - 1;
        }
    }
    /* invoke current debug_output routine */
    if (of_elf64.current_dfmt) {
        sinfo.offset = s->len;
        sinfo.section = i;
        sinfo.segto = segto;
        sinfo.name = s->name;
        of_elf64.current_dfmt->debug_output(TY_DEBUGSYMLIN, &sinfo);
    }
    /* end of debugging stuff */

    if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
        error(ERR_WARNING, "attempt to initialize memory in"
              " BSS section `%s': ignored", s->name);
	switch (type) {
	case OUT_REL2ADR:
	    size = 2;
	    break;
	case OUT_REL4ADR:
	    size = 4;
	    break;
	case OUT_REL8ADR:
	    size = 8;
	    break;
	default:
	    break;		/* size is already set */
	}
        s->len += size;
        return;
    }

    if (type == OUT_RESERVE) {
        if (s->type == SHT_PROGBITS) {
            error(ERR_WARNING, "uninitialized space declared in"
                  " non-BSS section `%s': zeroing", s->name);
            elf_sect_write(s, NULL, size);
        } else
            s->len += size;
    } else if (type == OUT_RAWDATA) {
        if (segment != NO_SEG)
            error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
        elf_sect_write(s, data, size);
    } else if (type == OUT_ADDRESS) {
        addr = *(int64_t *)data;
        if (segment == NO_SEG) {
	    /* Do nothing */
	} else if (segment % 2) {
	    error(ERR_NONFATAL, "ELF format does not support"
		  " segment base references");
	} else {
	    if (wrt == NO_SEG) {
		switch ((int)size) {
		case 1:
		    elf_add_reloc(s, segment, addr, R_X86_64_8);
		    break;
		case 2:
		    elf_add_reloc(s, segment, addr, R_X86_64_16);
		    break;
		case 4:
		    elf_add_reloc(s, segment, addr, R_X86_64_32);
		    break;
		case 8:
		    elf_add_reloc(s, segment, addr, R_X86_64_64);
		    break;
		default:
		    error(ERR_PANIC, "internal error elf64-hpa-871");
		    break;
		}
		addr = 0;
	    } else if (wrt == elf_gotpc_sect + 1) {
		/*
		 * The user will supply GOT relative to $$. ELF
		 * will let us have GOT relative to $. So we
		 * need to fix up the data item by $-$$.
		 */
		addr += s->len;
		elf_add_reloc(s, segment, addr, R_X86_64_GOTPC32);
		addr = 0;
	    } else if (wrt == elf_gotoff_sect + 1) {
		if (size != 8) {
		    error(ERR_NONFATAL, "ELF64 requires ..gotoff "
			  "references to be qword absolute");
		} else {
		    elf_add_reloc(s, segment, addr, R_X86_64_GOTOFF64);
		    addr = 0;
		}
	    } else if (wrt == elf_got_sect + 1) {
		switch ((int)size) {
		case 4:
		    elf_add_gsym_reloc(s, segment, addr, 0,
				       R_X86_64_GOT32, true);
		    addr = 0;
		    break;
		case 8:
		    elf_add_gsym_reloc(s, segment, addr, 0,
				       R_X86_64_GOT64, true);
		    addr = 0;
		    break;
		default:
		    error(ERR_NONFATAL, "invalid ..got reference");
		    break;
		}
	    } else if (wrt == elf_sym_sect + 1) {
		switch ((int)size) {
		case 1:
		    elf_add_gsym_reloc(s, segment, addr, 0,
				       R_X86_64_8, false);
		    addr = 0;
		    break;
		case 2:
		    elf_add_gsym_reloc(s, segment, addr, 0,
				       R_X86_64_16, false);
		    addr = 0;
		    break;
		case 4:
		    elf_add_gsym_reloc(s, segment, addr, 0,
				       R_X86_64_32, false);
		    addr = 0;
		    break;
		case 8:
		    elf_add_gsym_reloc(s, segment, addr, 0,
				       R_X86_64_64, false);
		    addr = 0;
		    break;
		default:
		    error(ERR_PANIC, "internal error elf64-hpa-903");
		    break;
		}
	    } else if (wrt == elf_plt_sect + 1) {
		error(ERR_NONFATAL, "ELF format cannot produce non-PC-"
		      "relative PLT references");
	    } else {
		error(ERR_NONFATAL, "ELF format does not support this"
		      " use of WRT");
	    }
	}
	elf_sect_writeaddr(s, addr, size);
    } else if (type == OUT_REL2ADR) {
	addr = *(int64_t *)data;
        if (segment == segto)
            error(ERR_PANIC, "intra-segment OUT_REL2ADR");
        if (segment == NO_SEG) {
	    /* Do nothing */
	} else if (segment % 2) {
            error(ERR_NONFATAL, "ELF format does not support"
                  " segment base references");
        } else {
            if (wrt == NO_SEG) {
                elf_add_reloc(s, segment, addr-size, R_X86_64_PC16);
		addr = 0;
            } else {
                error(ERR_NONFATAL,
                      "Unsupported non-32-bit ELF relocation [2]");
            }
        }
	elf_sect_writeaddr(s, addr, 2);
    } else if (type == OUT_REL4ADR) {
	addr = *(int64_t *)data;
        if (segment == segto)
            error(ERR_PANIC, "intra-segment OUT_REL4ADR");
        if (segment == NO_SEG) {
	    /* Do nothing */
	} else if (segment % 2) {
            error(ERR_NONFATAL, "ELF64 format does not support"
                  " segment base references");
        } else {
            if (wrt == NO_SEG) {
                elf_add_reloc(s, segment, addr-size, R_X86_64_PC32);
		addr = 0;
            } else if (wrt == elf_plt_sect + 1) {
                elf_add_gsym_reloc(s, segment, addr, size,
				   R_X86_64_PLT32, true);
		addr = 0;
            } else if (wrt == elf_gotpc_sect + 1 ||
		       wrt == elf_got_sect + 1) {
		printf("addr = %ld, pcrel = %ld\n", addr, size);
                elf_add_gsym_reloc(s, segment, addr, size,
				   R_X86_64_GOTPCREL, true);
		addr = 0;
            } else if (wrt == elf_gotoff_sect + 1 ||
		       wrt == elf_got_sect + 1) {
		error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be "
		      "qword absolute");
            } else {
                error(ERR_NONFATAL, "ELF64 format does not support this"
                      " use of WRT");
            }
        }
	elf_sect_writeaddr(s, addr, 4);
    } else if (type == OUT_REL8ADR) {
	addr = *(int64_t *)data;
        if (segment == segto)
            error(ERR_PANIC, "intra-segment OUT_REL8ADR");
        if (segment == NO_SEG) {
	    /* Do nothing */
	} else if (segment % 2) {
            error(ERR_NONFATAL, "ELF64 format does not support"
                  " segment base references");
        } else {
            if (wrt == NO_SEG) {
                elf_add_reloc(s, segment, addr-size, R_X86_64_PC64);
		addr = 0;
            } else if (wrt == elf_gotpc_sect + 1 ||
		       wrt == elf_got_sect + 1) {
                elf_add_gsym_reloc(s, segment, addr, size,
				   R_X86_64_GOTPCREL64, true);
		addr = 0;
            } else if (wrt == elf_gotoff_sect + 1 ||
		       wrt == elf_got_sect + 1) {
		error(ERR_NONFATAL, "ELF64 requires ..gotoff references to be "
		      "qword absolute");
            } else {
                error(ERR_NONFATAL, "ELF64 format does not support this"
                      " use of WRT");
            }
        }
        elf_sect_writeaddr(s, addr, 8);
    }
}

static void elf_write(void)
{
    int align;
    int scount;
    char *p;
    int commlen;
    char comment[64];
    int i;

    struct SAA *symtab;
    int32_t symtablen, symtablocal;

    /*
     * Work out how many sections we will have. We have SHN_UNDEF,
     * then the flexible user sections, then the four fixed
     * sections `.comment', `.shstrtab', `.symtab' and `.strtab',
     * then optionally relocation sections for the user sections.
     */
    if (of_elf64.current_dfmt == &df_stabs)
        nsections = 8;
    else if (of_elf64.current_dfmt == &df_dwarf)
        nsections = 15;
    else
        nsections = 5;          /* SHN_UNDEF and the fixed ones */

    add_sectname("", ".comment");
    add_sectname("", ".shstrtab");
    add_sectname("", ".symtab");
    add_sectname("", ".strtab");
    for (i = 0; i < nsects; i++) {
        nsections++;            /* for the section itself */
        if (sects[i]->head) {
            nsections++;        /* for its relocations */
            add_sectname(".rela", sects[i]->name);
        }
    }

    if (of_elf64.current_dfmt == &df_stabs) {
        /* in case the debug information is wanted, just add these three sections... */
        add_sectname("", ".stab");
        add_sectname("", ".stabstr");
        add_sectname(".rel", ".stab");
    }

    else if (of_elf64.current_dfmt == &df_dwarf) {
        /* the dwarf debug standard specifies the following ten sections,
           not all of which are currently implemented,
           although all of them are defined. */
        #define debug_aranges (int64_t) (nsections-10)
        #define debug_info (int64_t) (nsections-7)
        #define debug_abbrev (int64_t) (nsections-5)
        #define debug_line (int64_t) (nsections-4)

⌨️ 快捷键说明

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