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);
}
}
|