📄 outaout.c
字号:
} else if (segment == sdata.index) {
sym->type |= SECT_DATA;
if (is_global) {
sym->next = sdata.gsyms;
sdata.gsyms = sym;
} else if (!sdata.asym)
sdata.asym = sym;
} else if (segment == sbss.index) {
sym->type |= SECT_BSS;
if (is_global) {
sym->next = sbss.gsyms;
sbss.gsyms = sym;
} else if (!sbss.asym)
sbss.asym = sym;
} else
sym->type = SYM_GLOBAL;
if (is_global == 2)
sym->value = offset;
else
sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
if (is_global && sym->type != SYM_GLOBAL) {
/*
* Global symbol exported _from_ this module. We must check
* the special text for type information.
*/
if (special) {
int n = strcspn(special, " ");
if (!nasm_strnicmp(special, "function", n))
sym->type |= SYM_FUNCTION;
else if (!nasm_strnicmp(special, "data", n) ||
!nasm_strnicmp(special, "object", n))
sym->type |= SYM_DATA;
else
error(ERR_NONFATAL, "unrecognised symbol type `%.*s'",
n, special);
if (special[n]) {
struct tokenval tokval;
expr *e;
int fwd = false;
char *saveme = stdscan_bufptr; /* bugfix? fbk 8/10/00 */
if (!bsd) {
error(ERR_NONFATAL, "Linux a.out does not support"
" symbol size information");
} else {
while (special[n] && isspace(special[n]))
n++;
/*
* We have a size expression; attempt to
* evaluate it.
*/
sym->type |= SYM_WITH_SIZE;
stdscan_reset();
stdscan_bufptr = special + n;
tokval.t_type = TOKEN_INVALID;
e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error,
NULL);
if (fwd) {
sym->nextfwd = fwds;
fwds = sym;
sym->name = nasm_strdup(name);
} else if (e) {
if (!is_simple(e))
error(ERR_NONFATAL, "cannot use relocatable"
" expression as symbol size");
else
sym->size = reloc_value(e);
}
}
stdscan_bufptr = saveme; /* bugfix? fbk 8/10/00 */
}
special_used = true;
}
}
/*
* define the references from external-symbol segment numbers
* to these symbol records.
*/
if (segment != NO_SEG && segment != stext.index &&
segment != sdata.index && segment != sbss.index)
bsym = raa_write(bsym, segment, nsyms);
sym->symnum = nsyms;
nsyms++;
if (sym->type & SYM_WITH_SIZE)
nsyms++; /* and another for the size */
if (special && !special_used)
error(ERR_NONFATAL, "no special symbol features supported here");
}
static void aout_add_reloc(struct Section *sect, int32_t segment,
int reltype, int bytes)
{
struct Reloc *r;
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
sect->tail = &r->next;
r->next = NULL;
r->address = sect->len;
r->symbol = (segment == NO_SEG ? -SECT_ABS :
segment == stext.index ? -SECT_TEXT :
segment == sdata.index ? -SECT_DATA :
segment == sbss.index ? -SECT_BSS :
raa_read(bsym, segment));
r->reltype = reltype;
if (r->symbol >= 0)
r->reltype |= RELTYPE_SYMFLAG;
r->bytes = bytes;
sect->nrelocs++;
}
/*
* This routine deals with ..got and ..sym relocations: the more
* 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.
*
* RELTYPE_GOT references require the _exact_ symbol address to be
* used; RELTYPE_ABSOLUTE 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 int32_t aout_add_gsym_reloc(struct Section *sect,
int32_t segment, int32_t offset,
int type, int bytes, int exact)
{
struct Symbol *sym, *sm, *shead;
struct Reloc *r;
/*
* First look up the segment to find whether it's text, data,
* bss or an external symbol.
*/
shead = NULL;
if (segment == stext.index)
shead = stext.gsyms;
else if (segment == sdata.index)
shead = sdata.gsyms;
else if (segment == sbss.index)
shead = sbss.gsyms;
if (!shead) {
if (exact && offset != 0)
error(ERR_NONFATAL, "unable to find a suitable global symbol"
" for this reference");
else
aout_add_reloc(sect, segment, type, bytes);
return offset;
}
if (exact) {
/*
* Find a symbol pointing _exactly_ at this one.
*/
for (sym = shead; sym; sym = sym->next)
if (sym->value == offset)
break;
} else {
/*
* Find the nearest symbol below this one.
*/
sym = NULL;
for (sm = shead; sm; sm = sm->next)
if (sm->value <= offset && (!sym || sm->value > sym->value))
sym = sm;
}
if (!sym && exact) {
error(ERR_NONFATAL, "unable to find a suitable global symbol"
" for this reference");
return 0;
}
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
sect->tail = &r->next;
r->next = NULL;
r->address = sect->len;
r->symbol = sym->symnum;
r->reltype = type | RELTYPE_SYMFLAG;
r->bytes = bytes;
sect->nrelocs++;
return offset - sym->value;
}
/*
* This routine deals with ..gotoff relocations. These _must_ refer
* to a symbol, due to a perversity of *BSD's PIC implementation,
* and it must be a non-global one as well; so we store `asym', the
* first nonglobal symbol defined in each section, and always work
* from that. Relocation type is always RELTYPE_GOTOFF.
*
* Return value is the adjusted value of `addr', having become an
* offset from the `asym' symbol rather than the section.
*/
static int32_t aout_add_gotoff_reloc(struct Section *sect, int32_t segment,
int32_t offset, int bytes)
{
struct Reloc *r;
struct Symbol *asym;
/*
* First look up the segment to find whether it's text, data,
* bss or an external symbol.
*/
asym = NULL;
if (segment == stext.index)
asym = stext.asym;
else if (segment == sdata.index)
asym = sdata.asym;
else if (segment == sbss.index)
asym = sbss.asym;
if (!asym)
error(ERR_NONFATAL, "`..gotoff' relocations require a non-global"
" symbol in the section");
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
sect->tail = &r->next;
r->next = NULL;
r->address = sect->len;
r->symbol = asym->symnum;
r->reltype = RELTYPE_GOTOFF;
r->bytes = bytes;
sect->nrelocs++;
return offset - asym->value;
}
static void aout_out(int32_t segto, const void *data, uint32_t type,
int32_t segment, int32_t wrt)
{
struct Section *s;
int32_t realbytes = type & OUT_SIZMASK;
int32_t addr;
uint8_t mydata[4], *p;
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;
}
if (segto == stext.index)
s = &stext;
else if (segto == sdata.index)
s = &sdata;
else if (segto == sbss.index)
s = NULL;
else {
error(ERR_WARNING, "attempt to assemble code in"
" segment %d: defaulting to `.text'", segto);
s = &stext;
}
if (!s && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialize memory in the"
" BSS section: ignored");
if (type == OUT_REL2ADR)
realbytes = 2;
else if (type == OUT_REL4ADR)
realbytes = 4;
sbss.len += realbytes;
return;
}
if (type == OUT_RESERVE) {
if (s) {
error(ERR_WARNING, "uninitialized space declared in"
" %s section: zeroing",
(segto == stext.index ? "code" : "data"));
aout_sect_write(s, NULL, realbytes);
} else
sbss.len += realbytes;
} else if (type == OUT_RAWDATA) {
if (segment != NO_SEG)
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
aout_sect_write(s, data, realbytes);
} else if (type == OUT_ADDRESS) {
addr = *(int32_t *)data;
if (segment != NO_SEG) {
if (segment % 2) {
error(ERR_NONFATAL, "a.out format does not support"
" segment base references");
} else {
if (wrt == NO_SEG) {
aout_add_reloc(s, segment, RELTYPE_ABSOLUTE,
realbytes);
} else if (!bsd) {
error(ERR_NONFATAL,
"Linux a.out format does not support"
" any use of WRT");
wrt = NO_SEG; /* we can at least _try_ to continue */
} else if (wrt == aout_gotpc_sect + 1) {
is_pic = 0x40;
aout_add_reloc(s, segment, RELTYPE_GOTPC, realbytes);
} else if (wrt == aout_gotoff_sect + 1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -