mirror of
https://github.com/netwide-assembler/nasm.git
synced 2024-11-27 08:10:07 +08:00
d390490089
Otherwise getting building problem > output/outlib.c:197:6: error: no previous prototype for ‘ol_add_sym_to’ [-Werror=missing-prototypes] > 197 | void ol_add_sym_to(struct ol_symlist *syml, struct ol_symhead *head, > | ^~~~~~~~~~~~~ Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
325 lines
9.0 KiB
C
325 lines
9.0 KiB
C
/* ----------------------------------------------------------------------- *
|
|
*
|
|
* Copyright 1996-2020 The NASM Authors - All Rights Reserved
|
|
* See the file AUTHORS included with the NASM distribution for
|
|
* the specific copyright holders.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following
|
|
* conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* outlib.c
|
|
*
|
|
* Common routines for the output backends.
|
|
*/
|
|
|
|
#include "outlib.h"
|
|
#include "raa.h"
|
|
|
|
uint64_t realsize(enum out_type type, uint64_t size)
|
|
{
|
|
switch (type) {
|
|
case OUT_REL1ADR:
|
|
return 1;
|
|
case OUT_REL2ADR:
|
|
return 2;
|
|
case OUT_REL4ADR:
|
|
return 4;
|
|
case OUT_REL8ADR:
|
|
return 8;
|
|
default:
|
|
return size;
|
|
}
|
|
}
|
|
|
|
/* Common section/symbol handling */
|
|
|
|
struct ol_sect *_ol_sect_list;
|
|
uint64_t _ol_nsects; /* True sections, not external symbols */
|
|
static struct ol_sect **ol_sect_tail = &_ol_sect_list;
|
|
static struct hash_table ol_secthash;
|
|
static struct RAA *ol_sect_index_tbl;
|
|
|
|
struct ol_sym *_ol_sym_list;
|
|
uint64_t _ol_nsyms;
|
|
static struct ol_sym **ol_sym_tail = &_ol_sym_list;
|
|
static struct hash_table ol_symhash;
|
|
|
|
void ol_init(void)
|
|
{
|
|
}
|
|
|
|
static void ol_free_symbols(void)
|
|
{
|
|
struct ol_sym *s, *stmp;
|
|
|
|
hash_free(&ol_symhash);
|
|
|
|
list_for_each_safe(s, stmp, _ol_sym_list) {
|
|
nasm_free((char *)s->name);
|
|
nasm_free(s);
|
|
}
|
|
|
|
_ol_nsyms = 0;
|
|
_ol_sym_list = NULL;
|
|
ol_sym_tail = &_ol_sym_list;
|
|
}
|
|
|
|
static void ol_free_sections(void)
|
|
{
|
|
struct ol_sect *s, *stmp;
|
|
|
|
hash_free(&ol_secthash);
|
|
raa_free(ol_sect_index_tbl);
|
|
ol_sect_index_tbl = NULL;
|
|
|
|
list_for_each_safe(s, stmp, _ol_sect_list) {
|
|
saa_free(s->data);
|
|
saa_free(s->reloc);
|
|
nasm_free((char *)s->name);
|
|
nasm_free(s);
|
|
}
|
|
|
|
_ol_nsects = 0;
|
|
_ol_sect_list = NULL;
|
|
ol_sect_tail = &_ol_sect_list;
|
|
}
|
|
|
|
void ol_cleanup(void)
|
|
{
|
|
ol_free_symbols();
|
|
ol_free_sections();
|
|
}
|
|
|
|
/*
|
|
* Allocate a section index and add a section, subsection, or external
|
|
* symbol to the section-by-index table. If the index provided is zero,
|
|
* allocate a new index via seg_alloc().
|
|
*/
|
|
static uint32_t ol_seg_alloc(void *s, uint32_t ix)
|
|
{
|
|
if (!ix)
|
|
ix = seg_alloc();
|
|
ol_sect_index_tbl = raa_write_ptr(ol_sect_index_tbl, ix >> 1, s);
|
|
return ix;
|
|
}
|
|
|
|
/*
|
|
* Find a section or create a new section structure if it does not exist
|
|
* and allocate it an index value via seg_alloc().
|
|
*/
|
|
struct ol_sect *_ol_get_sect(const char *name, size_t ssize, size_t rsize)
|
|
{
|
|
struct ol_sect *s, **sp;
|
|
struct hash_insert hi;
|
|
|
|
sp = (struct ol_sect **)hash_find(&ol_secthash, name, &hi);
|
|
if (sp)
|
|
return *sp;
|
|
|
|
s = nasm_zalloc(ssize);
|
|
s->syml.tail = &s->syml.head;
|
|
s->name = nasm_strdup(name);
|
|
s->data = saa_init(1);
|
|
s->reloc = saa_init(rsize);
|
|
*ol_sect_tail = s;
|
|
ol_sect_tail = &s->next;
|
|
_ol_nsects++;
|
|
s->index = s->subindex = ol_seg_alloc(s, 0);
|
|
|
|
hash_add(&hi, s->name, s);
|
|
return s;
|
|
}
|
|
|
|
/* Find a section by name without creating one */
|
|
struct ol_sect *_ol_sect_by_name(const char *name)
|
|
{
|
|
struct ol_sect **sp;
|
|
|
|
sp = (struct ol_sect **)hash_find(&ol_secthash, name, NULL);
|
|
return sp ? *sp : NULL;
|
|
}
|
|
|
|
/* Find a section or external symbol by index; NULL if not valid */
|
|
struct ol_sect *_ol_sect_by_index(int32_t index)
|
|
{
|
|
uint32_t ix = index;
|
|
|
|
if (unlikely(ix >= SEG_ABS))
|
|
return NULL;
|
|
|
|
return raa_read_ptr(ol_sect_index_tbl, ix >> 1);
|
|
}
|
|
|
|
/*
|
|
* Start a new subsection for the given section. At the moment, once a
|
|
* subsection has been created, it is not possible to revert to an
|
|
* earlier subsection. ol_sect_by_index() will return the main section
|
|
* structure. Returns the new section index. This is used to prevent
|
|
* the front end from optimizing across subsection boundaries.
|
|
*/
|
|
int32_t _ol_new_subsection(struct ol_sect *sect)
|
|
{
|
|
if (unlikely(!sect))
|
|
return NO_SEG;
|
|
|
|
return sect->subindex = ol_seg_alloc(sect, 0);
|
|
}
|
|
|
|
/*
|
|
* Insert a symbol into a list; need to use upcasting using container_of()
|
|
* to walk the list later.
|
|
*/
|
|
static void ol_add_sym_to(struct ol_symlist *syml, struct ol_symhead *head,
|
|
uint64_t offset)
|
|
{
|
|
syml->tree.key = offset;
|
|
head->tree = rb_insert(head->tree, &syml->tree);
|
|
*head->tail = syml;
|
|
head->tail = &syml->next;
|
|
head->n++;
|
|
}
|
|
|
|
/*
|
|
* Create a location structure from seg:offs
|
|
*/
|
|
void ol_mkloc(struct ol_loc *loc, int64_t offs, int32_t seg)
|
|
{
|
|
nasm_zero(*loc);
|
|
loc->offs = offs;
|
|
|
|
if (unlikely((uint32_t)seg >= SEG_ABS)) {
|
|
if (likely(seg == NO_SEG)) {
|
|
loc->seg.t = OS_NOSEG;
|
|
} else {
|
|
loc->seg.t = OS_ABS;
|
|
loc->seg.index = seg - SEG_ABS;
|
|
}
|
|
} else {
|
|
loc->seg.index = seg & ~1;
|
|
loc->seg.t = OS_SECT | (seg & 1);
|
|
loc->seg.s.sect = _ol_sect_by_index(loc->seg.index);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Create a new symbol. If this symbol is OS_OFFS, add it to the relevant
|
|
* section, too. If the symbol already exists, return NULL; this is
|
|
* different from ol_get_section() as a single section may be invoked
|
|
* many times. On the contrary, the front end will prevent a single symbol
|
|
* from being defined more than once.
|
|
*
|
|
* If flags has OF_GLOBAL set, add it to the global symbol hash for
|
|
* the containing section if applicable.
|
|
*
|
|
* If flags has OF_IMPSEC set, allocate a segment index for it via
|
|
* seg_alloc() unless v->index is already set, and add it to the
|
|
* section by index list.
|
|
*/
|
|
struct ol_sym *_ol_new_sym(const char *name, const struct ol_loc *v,
|
|
uint32_t flags, size_t size)
|
|
{
|
|
struct hash_insert hi;
|
|
struct ol_sym *sym;
|
|
|
|
if (hash_find(&ol_symhash, name, &hi))
|
|
return NULL; /* Symbol already exists */
|
|
|
|
flags |= OF_SYMBOL;
|
|
|
|
sym = nasm_zalloc(size);
|
|
sym->name = nasm_strdup(name);
|
|
sym->v = *v;
|
|
|
|
if (sym->v.seg.t & OS_SECT) {
|
|
struct ol_sect *sect = sym->v.seg.s.sect;
|
|
|
|
if (!sect || (sect->flags & OF_SYMBOL))
|
|
/* Must be an external or common reference */
|
|
flags |= OF_IMPSEC;
|
|
|
|
if (flags & OF_IMPSEC) {
|
|
/* Metasection */
|
|
if (!sym->v.seg.s.sym) {
|
|
sym->v.seg.s.sym = sym;
|
|
sym->v.seg.index = ol_seg_alloc(sym, sym->v.seg.index);
|
|
}
|
|
} else if (sym->v.seg.t == OS_OFFS) {
|
|
struct ol_sect * const sect = sym->v.seg.s.sect;
|
|
const uint64_t offs = sym->v.offs;
|
|
|
|
ol_add_sym_to(&sym->syml, §->syml, offs);
|
|
if (flags & OF_GLOBAL)
|
|
ol_add_sym_to(&sym->symg, §->symg, offs);
|
|
}
|
|
}
|
|
sym->flags = flags;
|
|
|
|
*ol_sym_tail = sym;
|
|
ol_sym_tail = &sym->next;
|
|
_ol_nsyms++;
|
|
|
|
hash_add(&hi, sym->name, sym);
|
|
return sym;
|
|
}
|
|
|
|
/* Find a symbol in the global namespace */
|
|
struct ol_sym *_ol_sym_by_name(const char *name)
|
|
{
|
|
struct ol_sym **symp;
|
|
|
|
symp = (struct ol_sym **)hash_find(&ol_symhash, name, NULL);
|
|
return symp ? *symp : NULL;
|
|
}
|
|
|
|
/*
|
|
* Find a symbol by address in a specific section. If no symbol is defined
|
|
* at that exact address, return the immediately previously defined one.
|
|
* If global is set, then only return global symbols.
|
|
*/
|
|
struct ol_sym *_ol_sym_by_address(struct ol_sect *sect, int64_t addr,
|
|
bool global)
|
|
{
|
|
struct ol_symhead *head;
|
|
size_t t_offs;
|
|
struct rbtree *t;
|
|
|
|
if (global) {
|
|
head = §->symg;
|
|
t_offs = offsetof(struct ol_sym, symg.tree);
|
|
} else {
|
|
head = §->syml;
|
|
t_offs = offsetof(struct ol_sym, syml.tree);
|
|
}
|
|
|
|
t = rb_search(head->tree, addr);
|
|
if (!t)
|
|
return NULL;
|
|
|
|
return (struct ol_sym *)((char *)t - t_offs);
|
|
}
|