Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1291984
  • 博文数量: 196
  • 博客积分: 4141
  • 博客等级: 中将
  • 技术积分: 2253
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-21 20:04
文章存档

2019年(31)

2016年(1)

2014年(16)

2011年(8)

2010年(25)

2009年(115)

分类: LINUX

2009-03-22 12:31:18

static void elf_out(long segto, const void *data, unsigned long type, long segment, long wrt)
{
    struct Section *s;
    long realbytes = type & OUT_SIZMASK;
    long addr;
    unsigned char mydata[4], *p;
    int i;
    static struct symlininfo sinfo;

    type &= OUT_TYPMASK;

    /*
     * handle absolute-assembly (structure definitions)
     */

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

    /* 获取 section */
    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;
        }
    }

    /* again some stabs debugging stuff */
    if (of_elf.current_dfmt) {
        sinfo.offset = s->len;
        sinfo.section = i;
        sinfo.name = s->name;
        of_elf.current_dfmt->debug_output(TY_STABSSYMLIN, &sinfo);
    }
    /* end of debugging stuff */

    /* s->type == SHT_NOBITS 的情况下,为真正写入数据,仅仅实现做了 s->len 的加法运算 */
    if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
        error(ERR_WARNING, "attempt to initialise memory in BSS section `%s': ignored", s->name);
        if (type == OUT_REL2ADR)
            realbytes = 2;
        else if (type == OUT_REL4ADR)
            realbytes = 4;
        s->len += realbytes;
        return;
    }

    if (type == OUT_RESERVE) { /* BSS */
        if (s->type == SHT_PROGBITS) {
            error(ERR_WARNING, "uninitialised space declared in non-BSS section `%s': zeroing", s->name);
            elf_sect_write(s, NULL, realbytes); /* 在 non-BSS 中进行未初始化声明,则自动初始化为 0 */
        } else
            s->len += realbytes;
    } else if (type == OUT_RAWDATA) { /* 输出数据,Data */
        if (segment != NO_SEG)
            error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
        elf_sect_write(s, data, realbytes);
    } else if (type == OUT_ADDRESS) {
        int gnu16 = 0;
        addr = *(long *)data;
        if (segment != NO_SEG) {
            if (segment % 2) { /* 如果出现 seg XXX, 则 segment % 2 == 1 */
                error(ERR_NONFATAL, "ELF format does not support segment base references");
            } else {
                if (wrt == NO_SEG) {
                    if (realbytes == 2) {
                        gnu16 = 1;
                        elf_add_reloc(s, segment, R_386_16);
                    } else {
                        elf_add_reloc(s, segment, R_386_32); /* 存放的是数据 */
                    }
                /* 处理 wrt ..XXX 重定位 */
                } 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, R_386_GOTPC);
                } else if (wrt == elf_gotoff_sect + 1) {
                    elf_add_reloc(s, segment, R_386_GOTOFF);
                } else if (wrt == elf_got_sect + 1) {
                    addr = elf_add_gsym_reloc(s, segment, addr, R_386_GOT32, TRUE);
                } else if (wrt == elf_sym_sect + 1) {
                    if (realbytes == 2) {
                        gnu16 = 1;
                        addr = elf_add_gsym_reloc(s, segment, addr, R_386_16, FALSE);
                    } else {
                        addr = elf_add_gsym_reloc(s, segment, addr, R_386_32, FALSE);
                    }
                } 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");
                    wrt = NO_SEG; /* we can at least _try_ to continue */
                }
            }
        }
        p = mydata;
        if (gnu16) {
            error(ERR_WARNING | ERR_WARN_GNUELF, "16-bit relocations in ELF is a GNU extension");
            WRITESHORT(p, addr);
        } else {
            if (realbytes != 4 && segment != NO_SEG) {
                error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation");
            }
            WRITELONG(p, addr);
        }
        elf_sect_write(s, mydata, realbytes);
    } else if (type == OUT_REL2ADR) {
        if (segment == segto)
            error(ERR_PANIC, "intra-segment OUT_REL2ADR"); /* 同一个段内不需要重定位 */
        if (segment != NO_SEG && segment % 2) {
            error(ERR_NONFATAL, "ELF format does not support segment base references");
        } else {
            if (wrt == NO_SEG) {
                error(ERR_WARNING | ERR_WARN_GNUELF, "16-bit relocations in ELF is a GNU extension");
                elf_add_reloc(s, segment, R_386_PC16);
            } else {
                error(ERR_NONFATAL, "Unsupported non-32-bit ELF relocation");
            }
        }
        p = mydata;
        WRITESHORT(p, *(long *)data - realbytes);
        elf_sect_write(s, mydata, 2L);
    } else if (type == OUT_REL4ADR) {
        if (segment == segto)
            error(ERR_PANIC, "intra-segment OUT_REL4ADR");
        if (segment != NO_SEG && segment % 2) {
            error(ERR_NONFATAL, "ELF format does not support segment base references");
        } else {
            if (wrt == NO_SEG) {
                elf_add_reloc(s, segment, R_386_PC32); /* [section .txt], 其中 .txt 是该类型,其中该段内存放的是指令 */
            } else if (wrt == elf_plt_sect + 1) {
                elf_add_reloc(s, segment, R_386_PLT32); /* 只能用在 call, jmp 指令,例如 call func wrt ..plt */
            } else if (wrt == elf_gotpc_sect + 1 || wrt == elf_gotoff_sect + 1 || wrt == elf_got_sect + 1) {
                error(ERR_NONFATAL, "ELF format cannot produce PC-relative GOT references");
            } else {
                error(ERR_NONFATAL, "ELF format does not support this use of WRT");
                wrt = NO_SEG; /* we can at least _try_ to continue */
            }
        }
        p = mydata;
        WRITELONG(p, *(long *)data - realbytes);
        elf_sect_write(s, mydata, 4L);
    }
}

阅读(2711) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~