Fix #44 by adding support for WRT special symbols (e.g. [sym WRT ..plt] and

similar) to ELF.  They are used identically to NASM's ELF shared object
support.

Due to limited WRT support throughout libyasm, this caused a lot of rippling
changes.  A major cleanup needs to be performed later to clear some of this
hackiness up.

* elf-machine.h (func_accepts_size_t): Rename to func_accepts_reloc().
(func_map_reloc_info_to_type): Add parameter ssyms for array of special syms.
(elf_machine_ssym): New; for defining machine-specific special syms.
(elf_machine_handler): Change accepts_reloc_size to accepts_reloc.  Add new
ssyms and num_ssyms members.

* elf-x86-x86.c (ssym_index): New; this allows nice indexing of ssym arrays.
(elf_x86_x86_accepts_reloc): Rename of elf_x86_x86_accepts_reloc_size.  Add
support for various WRT ssyms.
(elf_x86_x86_map_reloc_info_to_type): Add support for various WRT ssyms.
(elf_x86_x86_ssyms): New array of supported special symbols.
(elf_machine_handler_x86_x86): Update for above changes/additions.
* elf-x86-amd64.c (ssym_index, elf_x86_amd64_accepts_reloc)
(elf_x86_amd64_map_reloc_info_to_type, elf_x86_amd64_ssyms)
(elf_machine_handler_x86_amd64): Likewise.

* elf.h (elf_reloc_entry): Add wrt member.
(elf_set_arch): Add symtab parameter.
(elf_is_wrt_sym_relative): New.
(elf_reloc_entry_create): Add wrt parameter.
* elf.c (elf_set_arch): Allocate special syms from machine level.
(elf_is_wrt_sym_relative): New; search special syms, and report whether a
WRT ssym should be symbol-relative or section-relative.
(elf_reloc_entry_create): Pass WRT and ssyms info down to machine level.

* elf-objfmt.c (yasm_objfmt_elf): Add dotdotsym (..sym) symrec member.
(elf_objfmt_create): Pass symtab to elf_set_arch().  Allocate ..sym symbol.
(elf_objfmt_output_reloc): Update for elf_reloc_entry_create() change.
(elf_objfmt_output_expr): Handle WRT ssym.  Make relocation symbol-relative
rather than section-relative if either WRT ..sym or WRT ssym that machine
level desires to be symbol-relative.

* symrec.c (yasm_symrec_get_label): Check for NULL sym->value.precbc; this
is now possible due to the user-accessible special symbols that ELF et al
create, which all have NULL precbc's.

* expr.c (yasm_expr_extract_symrec): Recurse into IDENT's to make more exprs
acceptable.

* coretype.h (yasm_output_reloc_func): Remove rel parameter as it shouldn't
be needed and complexifies writing of the reloc functions.
* stabs-dbgfmt.c (stabs_bc_stab_tobytes): Update output_reloc() call.
* elf-objfmt.c (elf_objfmt_output_reloc): Update to match.

* arch.h (yasm_arch_module): Add intnum_fixup_rel() function, change
intnum_tobytes() to not take rel parameter.  The rel functionality is being
separated because sometimes it's desirable not to put the data into the
written intnum (e.g. ELF RELA relocations).
(YASM_ARCH_VERSION): Bump due to above change.
(yasm_arch_intnum_fixup_rel): New wrapper.
(yasm_arch_intnum_tobytes): Update wrapper (removing rel).

* lc3bbc.c (yasm_lc3b__intnum_fixup_rel): New, with code from:
(yasm_lc3b__intnum_tobytes): Remove rel code.
* lc3barch.h (yasm_lc3b__intnum_fixup_rel): New.
(yasm_lc3b__intnum_tobytes): Update.
* lc3barch.c (yasm_lc3b_LTX_arch): Reference yasm_lc3b__intnum_fixup_rel().

* x86bc.c (yasm_x86__intnum_fixup_rel): New, with code from:
(yasm_x86__intnum_tobytes): Remove rel code.
* x86arch.h (yasm_x86__intnum_fixup_rel): New.
(yasm_x86__intnum_tobytes): Update.
* x86arch.c (yasm_x86_LTX_arch): Reference yasm_x86__intnum_fixup_rel().

* xdf-objfmt.c (xdf_objfmt_output_expr): Update to use intnum_fixup_rel() /
new intnum_tobytes().
* bin-objfmt.c (bin_objfmt_output_expr): Likewise.
* coff-objfmt.c (coff_objfmt_output_expr): Likewise.
* elf-objfmt.c (elf_objfmt_output_expr: Likewise.
* nasm-listfmt.c (nasm_listfmt_output_expr): Likewise.

* nasm-bison.y: Change precedence of WRT and : operators: instead of being
the strongest binders they are now the weakest.  This is needed to correctly
parse and be able to split WRT expressions.  WRT handling is still somewhat
of a hack throughout yasm; we'll fix this later.

* x86expr.c (x86_expr_checkea_distcheck_reg): Don't check for WRT here.
(x86_expr_checkea_getregusage): Add new wrt parameter.  Use it to handle
"WRT rip" separately from other operators.  Recurse if there's a WRT below
the WRT rip; this is to handle cases like ELF-AMD64's elfso64.asm.
(yasm_x86__expr_checkea): Split off top-level WRT's and feed through
separately to x86_expr_checkea_getregusage().

* x86bc.c (x86_bc_insn_tobytes): Ensure the SUB operation for PC-relative
displacements goes BELOW any WRT expression.
(x86_bc_jmp_tobytes): Likewise.

* elfso.asm, elfso.hex, elfso.errwarn: New 32-bit ELF shared object tests.
* modules/objfmts/elf/tests/Makefile.inc: Include in distribution.

* elfso64.asm, elfso64.hex, elfso64.errwarn: New 64-bit ELF shared object
tests.  This is not a good example, as the assembled code doesn't work, but
it at least tests the special symbols.
* modules/objfmts/elf/tests/amd64/Makefile.inc: Include in distribution.


svn path=/trunk/yasm/; revision=1168
This commit is contained in:
Peter Johnson 2004-10-31 01:07:52 +00:00
parent f5b1d4532d
commit 23e53d41ce
32 changed files with 3428 additions and 168 deletions

View file

@ -104,7 +104,7 @@ typedef struct yasm_arch_machine {
* module loader's function definitions. The version number must never be
* decreased.
*/
#define YASM_ARCH_VERSION 2
#define YASM_ARCH_VERSION 3
/** YASM architecture module interface.
* \note All "data" in parser-related functions (yasm_arch_parse_*) needs to
@ -208,12 +208,19 @@ typedef struct yasm_arch_module {
size_t valsize, size_t shift, int warn,
unsigned long line);
/** Module-level implementation of yasm_arch_intnum_fixup_rel().
* Call yasm_arch_intnum_fixup_rel() instead of calling this function.
*/
int (*intnum_fixup_rel) (yasm_arch *arch, yasm_intnum *intn,
size_t valsize, const yasm_bytecode *bc,
unsigned long line);
/** Module-level implementation of yasm_arch_intnum_tobytes().
* Call yasm_arch_intnum_tobytes() instead of calling this function.
*/
int (*intnum_tobytes) (yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
int shift, const yasm_bytecode *bc, int rel,
int shift, const yasm_bytecode *bc,
int warn, unsigned long line);
/** Module-level implementation of yasm_arch_get_reg_size().
@ -446,6 +453,19 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
size_t valsize, size_t shift, int warn,
unsigned long line);
/** Adjust #yasm_intnum for relative displacement from bc. Displacement
* is modified in-place.
* \param arch architecture
* \param intn integer value
* \param valsize size (in bits)
* \param bc bytecode being output ("parent" of value)
* \param line virtual line; may be 0 if warn is 0
* \return Nonzero on error.
*/
int yasm_arch_intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn,
size_t valsize, const yasm_bytecode *bc,
unsigned long line);
/** Output #yasm_intnum to buffer. Puts the value into the least
* significant bits of the destination, or may be shifted into more
* significant bits by the shift parameter. The destination bits are
@ -458,7 +478,6 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
* \param shift left shift (in bits); may be negative to specify right
* shift (standard warnings include truncation to boundary)
* \param bc bytecode being output ("parent" of value)
* \param rel value is a relative displacement from bc
* \param warn enables standard warnings (value doesn't fit into
* valsize bits)
* \param line virtual line; may be 0 if warn is 0
@ -467,7 +486,7 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt,
int yasm_arch_intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize,
size_t valsize, int shift,
const yasm_bytecode *bc, int rel, int warn,
const yasm_bytecode *bc, int warn,
unsigned long line);
/** Get the equivalent byte size of a register.
@ -541,10 +560,13 @@ yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e);
warn, line) \
((yasm_arch_base *)arch)->module->floatnum_tobytes \
(arch, flt, buf, destsize, valsize, shift, warn, line)
#define yasm_arch_intnum_fixup_rel(arch, intn, valsize, bc, line) \
((yasm_arch_base *)arch)->module->intnum_fixup_rel \
(arch, intn, valsize, bc, line)
#define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \
bc, rel, warn, line) \
bc, warn, line) \
((yasm_arch_base *)arch)->module->intnum_tobytes \
(arch, intn, buf, destsize, valsize, shift, bc, rel, warn, line)
(arch, intn, buf, destsize, valsize, shift, bc, warn, line)
#define yasm_arch_get_reg_size(arch, reg) \
((yasm_arch_base *)arch)->module->get_reg_size(arch, reg)
#define yasm_arch_reg_print(arch, reg, f) \

View file

@ -201,7 +201,6 @@ typedef int (*yasm_output_expr_func)
* \param buf buffer for byte representation
* \param destsize destination size (in bytes)
* \param valsize size (in bits)
* \param rel if nonzero, expr should be treated as PC/IP-relative
* \param warn enables standard warnings: zero for none;
* nonzero for overflow/underflow floating point warnings;
* negative for signed integer warnings,
@ -212,7 +211,7 @@ typedef int (*yasm_output_expr_func)
*/
typedef int (*yasm_output_reloc_func)
(yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf, size_t destsize,
size_t valsize, int rel, int warn, void *d);
size_t valsize, int warn, void *d);
/** Sort an array using merge sort algorithm.
* \internal

View file

@ -993,6 +993,10 @@ yasm_expr_extract_symrec(yasm_expr **ep, int relocate,
switch ((*ep)->op) {
case YASM_EXPR_IDENT:
/* Be kind, recurse */
if ((*ep)->terms[0].type == YASM_EXPR_EXPR)
return yasm_expr_extract_symrec(&((*ep)->terms[0].data.expn),
relocate, calc_bc_dist);
/* Replace sym with 0 value, return sym */
if ((*ep)->terms[0].type == YASM_EXPR_SYM) {
sym = (*ep)->terms[0].data.sym;

View file

@ -356,7 +356,7 @@ int
yasm_symrec_get_label(const yasm_symrec *sym,
yasm_symrec_get_label_bytecodep *precbc)
{
if (sym->type != SYM_LABEL) {
if (sym->type != SYM_LABEL || !sym->value.precbc) {
*precbc = (yasm_symrec_get_label_bytecodep)0xDEADBEEF;
return 0;
}

View file

@ -130,6 +130,7 @@ yasm_arch_module yasm_lc3b_LTX_arch = {
NULL, /*yasm_lc3b__parse_seg_prefix*/
NULL, /*yasm_lc3b__parse_seg_override*/
lc3b_floatnum_tobytes,
yasm_lc3b__intnum_fixup_rel,
yasm_lc3b__intnum_tobytes,
lc3b_get_reg_size,
lc3b_reg_print,

View file

@ -65,8 +65,12 @@ yasm_arch_check_id_retval yasm_lc3b__parse_check_id
/*@null@*/ yasm_insn_operands *operands, yasm_bytecode *prev_bc,
unsigned long line);
int yasm_lc3b__intnum_fixup_rel
(yasm_arch *arch, yasm_intnum *intn, size_t valsize,
const yasm_bytecode *bc, unsigned long line);
int yasm_lc3b__intnum_tobytes
(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
int rel, int warn, unsigned long line);
int warn, unsigned long line);
#endif

View file

@ -241,27 +241,28 @@ lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
}
int
yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
int shift, const yasm_bytecode *bc, int rel,
int warn, unsigned long line)
yasm_lc3b__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn,
size_t valsize, const yasm_bytecode *bc,
unsigned long line)
{
if (rel) {
yasm_intnum *relnum, *delta;
if (valsize != 9)
yasm_internal_error(
N_("tried to do PC-relative offset from invalid sized value"));
relnum = yasm_intnum_copy(intn);
delta = yasm_intnum_create_uint(bc->len);
yasm_intnum_calc(relnum, YASM_EXPR_SUB, delta, line);
yasm_intnum_destroy(delta);
yasm_intnum_get_sized(relnum, buf, destsize, valsize, shift, 0, warn,
line);
yasm_intnum_destroy(relnum);
} else {
/* Write value out. */
yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn,
line);
}
yasm_intnum *delta;
if (valsize != 9)
yasm_internal_error(
N_("tried to do PC-relative offset from invalid sized value"));
delta = yasm_intnum_create_uint(bc->len);
yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line);
yasm_intnum_destroy(delta);
return 0;
}
int
yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
int shift, const yasm_bytecode *bc, int warn,
unsigned long line)
{
/* Write value out. */
yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn,
line);
return 0;
}

View file

@ -263,6 +263,7 @@ yasm_arch_module yasm_x86_LTX_arch = {
x86_parse_seg_prefix,
x86_parse_seg_override,
yasm_x86__floatnum_tobytes,
yasm_x86__intnum_fixup_rel,
yasm_x86__intnum_tobytes,
yasm_x86__get_reg_size,
x86_reg_print,

View file

@ -218,10 +218,13 @@ int yasm_x86__floatnum_tobytes
(yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf,
size_t destsize, size_t valsize, size_t shift, int warn,
unsigned long line);
int yasm_x86__intnum_fixup_rel
(yasm_arch *arch, yasm_intnum *intn, size_t valsize,
const yasm_bytecode *bc, unsigned long line);
int yasm_x86__intnum_tobytes
(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf,
size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc,
int rel, int warn, unsigned long line);
int warn, unsigned long line);
unsigned int yasm_x86__get_reg_size(yasm_arch *arch, unsigned long reg);
#endif

View file

@ -1026,10 +1026,17 @@ x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
if (ea->disp) {
if (eat.pcrel) {
/*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp);
ea->disp =
yasm_expr_create(YASM_EXPR_SUB,
yasm_expr_expr(ea->disp),
yasm_expr_sym(eat.origin), bc->line);
if (wrt) {
ea->disp =
yasm_expr_create(YASM_EXPR_WRT,
yasm_expr_expr(ea->disp),
yasm_expr_expr(wrt), bc->line);
}
if (output_expr(&ea->disp, *bufp, ea->len,
(size_t)(ea->len*8), 0,
(unsigned long)(*bufp-bufp_orig), bc, 1, 1,
@ -1074,6 +1081,7 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
unsigned int i;
unsigned char *bufp_orig = *bufp;
/*@null@*/ yasm_expr *targetseg;
/*@null@*/ yasm_expr *wrt;
yasm_expr *dup;
/* Prefixes */
@ -1101,9 +1109,14 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
YASM_WRITE_8(*bufp, jmp->shortop.opcode[i]);
/* Relative displacement */
wrt = yasm_expr_extract_wrt(&jmp->target);
jmp->target =
yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
yasm_expr_sym(jmp->origin), bc->line);
if (wrt)
jmp->target = yasm_expr_create_tree(jmp->target,
YASM_EXPR_WRT, wrt,
bc->line);
if (output_expr(&jmp->target, *bufp, 1, 8, 0,
(unsigned long)(*bufp-bufp_orig), bc, 1, 1, d))
return 1;
@ -1122,9 +1135,14 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
YASM_WRITE_8(*bufp, jmp->nearop.opcode[i]);
/* Relative displacement */
wrt = yasm_expr_extract_wrt(&jmp->target);
jmp->target =
yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target),
yasm_expr_sym(jmp->origin), bc->line);
if (wrt)
jmp->target = yasm_expr_create_tree(jmp->target,
YASM_EXPR_WRT, wrt,
bc->line);
i = (opersize == 16) ? 2 : 4;
if (output_expr(&jmp->target, *bufp, i, i*8, 0,
(unsigned long)(*bufp-bufp_orig), bc, 1, 1, d))
@ -1169,27 +1187,27 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
}
int
yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
int shift, const yasm_bytecode *bc, int rel, int warn,
unsigned long line)
yasm_x86__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, size_t valsize,
const yasm_bytecode *bc, unsigned long line)
{
if (rel) {
yasm_intnum *relnum, *delta;
if (valsize != 8 && valsize != 16 && valsize != 32)
yasm_internal_error(
N_("tried to do PC-relative offset from invalid sized value"));
relnum = yasm_intnum_copy(intn);
delta = yasm_intnum_create_uint(bc->len);
yasm_intnum_calc(relnum, YASM_EXPR_SUB, delta, line);
yasm_intnum_destroy(delta);
yasm_intnum_get_sized(relnum, buf, destsize, valsize, shift, 0, warn,
line);
yasm_intnum_destroy(relnum);
} else {
/* Write value out. */
yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn,
line);
}
yasm_intnum *delta;
if (valsize != 8 && valsize != 16 && valsize != 32)
yasm_internal_error(
N_("tried to do PC-relative offset from invalid sized value"));
delta = yasm_intnum_create_uint(bc->len);
yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line);
yasm_intnum_destroy(delta);
return 0;
}
int
yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
unsigned char *buf, size_t destsize, size_t valsize,
int shift, const yasm_bytecode *bc, int warn,
unsigned long line)
{
/* Write value out. */
yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn,
line);
return 0;
}

View file

@ -157,11 +157,6 @@ x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits)
case YASM_EXPR_ADD:
case YASM_EXPR_IDENT:
break;
case YASM_EXPR_WRT:
/* Allow expr WRT rip in 64-bit mode. */
if (bits != 64 || i != 1)
return 0;
break;
default:
return 0;
}
@ -252,9 +247,9 @@ x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits)
* and 0 if all values successfully determined and saved in data.
*/
static int
x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
unsigned char *pcrel, unsigned int bits, void *data,
int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt,
/*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits,
void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d),
yasm_calc_bc_dist_func calc_bc_dist)
{
int i;
@ -267,6 +262,9 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
/*@-unqualifiedtrans@*/
*ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, calc_bc_dist, NULL,
NULL, NULL);
if (*wrt)
*wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, calc_bc_dist,
NULL, NULL, NULL);
/*@=unqualifiedtrans@*/
assert(*ep != NULL);
e = *ep;
@ -283,27 +281,31 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg,
break;
}
switch (e->op) {
case YASM_EXPR_WRT:
/* Handle xx WRT rip. */
if (e->terms[1].type == YASM_EXPR_REG) {
if (bits != 64) /* only valid in 64-bit mode */
return 1;
reg = get_reg(&e->terms[1], &regnum, data);
if (!reg || regnum != 16) /* only accept rip */
return 1;
(*reg)++;
if (*wrt && (*wrt)->op == YASM_EXPR_IDENT &&
(*wrt)->terms[0].type == YASM_EXPR_REG) {
/* Handle xx WRT rip. */
if (bits != 64) /* only valid in 64-bit mode */
return 1;
reg = get_reg(&(*wrt)->terms[0], &regnum, data);
if (!reg || regnum != 16) /* only accept rip */
return 1;
(*reg)++;
/* Simplify WRT to ident. Set pcrel to 1 to indicate to x86
* bytecode code to do PC-relative displacement transform.
*/
*pcrel = 1;
e->op = YASM_EXPR_IDENT;
e->numterms = 1;
/* Delete the intnum created by get_reg(). */
yasm_intnum_destroy(e->terms[1].data.intn);
}
break;
/* Delete WRT. Set pcrel to 1 to indicate to x86
* bytecode code to do PC-relative displacement transform.
*/
*pcrel = 1;
yasm_expr_destroy(*wrt);
/* Drill down to next WRT and recurse if there was one. */
*wrt = yasm_expr_extract_wrt(ep);
if (*wrt)
return x86_expr_checkea_getregusage(ep, wrt, indexreg, pcrel,
bits, data, get_reg,
calc_bc_dist);
}
switch (e->op) {
case YASM_EXPR_ADD:
/* Prescan for non-int multipliers against a reg.
* This is because if any of the terms is a more complex
@ -563,7 +565,12 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
unsigned char *rex,
yasm_calc_bc_dist_func calc_bc_dist)
{
yasm_expr *e = *ep;
yasm_expr *e, *wrt;
int retval;
/* First split off any top-level WRT. We'll add it back in at the end */
wrt = yasm_expr_extract_wrt(ep);
e = *ep;
if (*addrsize == 0) {
/* we need to figure out the address size from what we know about:
@ -651,7 +658,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
reg3264_data.regs = reg3264mult;
reg3264_data.bits = bits;
reg3264_data.addrsize = *addrsize;
switch (x86_expr_checkea_getregusage(ep, &indexreg, pcrel, bits,
switch (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits,
&reg3264_data,
x86_expr_checkea_get_reg3264,
calc_bc_dist)) {
@ -660,6 +667,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
yasm__error(e->line, N_("invalid effective address"));
return 1;
case 2:
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
(*ep)->line);
return 2;
default:
e = *ep;
@ -782,6 +792,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
/* RIP always requires a 32-bit displacement */
*v_modrm = 1;
*displen = 4;
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
(*ep)->line);
return 0;
} else if (indexreg == REG3264_NONE) {
/* basereg only */
@ -860,9 +873,12 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
}
/* Calculate displacement length (if possible) */
return x86_checkea_calc_displen(ep, 4, basereg == REG3264_NONE,
retval = x86_checkea_calc_displen(ep, 4, basereg == REG3264_NONE,
basereg == REG3264_EBP || basereg == REG64_R13, displen, modrm,
v_modrm);
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
return retval;
} else if (*addrsize == 16 && *n_modrm && !*v_modrm) {
static const unsigned char modrm16[16] = {
0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */,
@ -893,8 +909,8 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
*v_sib = 0;
*n_sib = 0;
switch (x86_expr_checkea_getregusage(ep, (int *)NULL, pcrel, bits,
&reg16mult,
switch (x86_expr_checkea_getregusage(ep, &wrt, (int *)NULL, pcrel,
bits, &reg16mult,
x86_expr_checkea_get_reg16,
calc_bc_dist)) {
case 1:
@ -902,6 +918,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
yasm__error(e->line, N_("invalid effective address"));
return 1;
case 2:
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt,
(*ep)->line);
return 2;
default:
e = *ep;
@ -935,9 +954,12 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
*modrm |= modrm16[havereg];
/* Calculate displacement length (if possible) */
return x86_checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
retval = x86_checkea_calc_displen(ep, 2, havereg == HAVE_NONE,
havereg == HAVE_BP, displen, modrm,
v_modrm);
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
return retval;
} else if (!*n_modrm && !*n_sib) {
/* Special case for MOV MemOffs opcode: displacement but no modrm. */
switch (*addrsize) {
@ -963,6 +985,8 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize,
break;
}
}
if (wrt)
*ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line);
return 0;
}

View file

@ -443,7 +443,7 @@ stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
if (stab->symvalue != NULL) {
bc->offset += 8;
output_reloc(stab->symvalue, bc, buf, 4, 32, 0, 0, d);
output_reloc(stab->symvalue, bc, buf, 4, 32, 0, d);
bc->offset -= 8;
buf += 4;
}

View file

@ -87,7 +87,7 @@ nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
/*@null@*/ void *d)
{
/*@null@*/ nasm_listfmt_output_info *info = (nasm_listfmt_output_info *)d;
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
assert(info != NULL);
@ -115,15 +115,14 @@ nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
if (shift < 0)
yasm_internal_error(N_("attempting to negative shift a float"));
return yasm_arch_floatnum_tobytes(info->arch, flt, buf, destsize,
valsize, (unsigned int)shift, warn,
valsize, (unsigned int)shift, 0,
bc->line);
}
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize,
valsize, shift, bc, rel, warn,
bc->line);
valsize, shift, bc, 0, bc->line);
return 0;
}

View file

@ -155,7 +155,7 @@ bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
int rel, int warn, /*@null@*/ void *d)
{
/*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d;
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
assert(info != NULL);
@ -180,10 +180,18 @@ bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
/* Handle integer expressions */
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
if (intn) {
if (rel) {
int retval = yasm_arch_intnum_fixup_rel(info->objfmt_bin->arch,
intn, valsize, bc,
bc->line);
if (retval)
return retval;
}
return yasm_arch_intnum_tobytes(info->objfmt_bin->arch, intn, buf,
destsize, valsize, shift, bc, rel,
warn, bc->line);
destsize, valsize, shift, bc, warn,
bc->line);
}
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {

View file

@ -361,7 +361,7 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
{
/*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d;
yasm_objfmt_coff *objfmt_coff;
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
/*@dependent@*/ /*@null@*/ yasm_symrec *sym;
/*@dependent@*/ yasm_section *label_sect;
@ -464,10 +464,16 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
}
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
if (intn) {
if (rel) {
int retval = yasm_arch_intnum_fixup_rel(objfmt_coff->arch, intn,
valsize, bc, bc->line);
if (retval)
return retval;
}
return yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize,
valsize, shift, bc, rel, warn,
bc->line);
valsize, shift, bc, warn, bc->line);
}
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {

View file

@ -44,7 +44,8 @@
#define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i)
typedef int(*func_accepts_size_t)(size_t);
typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt,
yasm_symrec **ssyms);
typedef void(*func_write_symtab_entry)(unsigned char *bufp,
elf_symtab_entry *entry,
yasm_intnum *value_intn,
@ -57,7 +58,8 @@ typedef void(*func_write_secthead_rel)(unsigned char *bufp,
typedef void(*func_handle_reloc_addend)(yasm_intnum *intn,
elf_reloc_entry *reloc);
typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc);
typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc,
yasm_symrec **ssyms);
typedef void(*func_write_reloc)(unsigned char *bufp,
elf_reloc_entry *reloc,
unsigned int r_type,
@ -67,6 +69,11 @@ typedef void (*func_write_proghead)(unsigned char **bufpp,
unsigned long secthead_count,
elf_section_index shstrtab_index);
typedef struct {
const char *name; /* should be something like ..name */
const int sym_rel; /* symbol or section-relative? */
} elf_machine_ssym;
typedef struct {
const char *arch;
const char *machine;
@ -76,7 +83,7 @@ typedef struct {
const unsigned long reloc_entry_size;
const unsigned long secthead_size;
const unsigned long proghead_size;
func_accepts_size_t accepts_reloc_size;
func_accepts_reloc accepts_reloc;
func_write_symtab_entry write_symtab_entry;
func_write_secthead write_secthead;
func_write_secthead_rel write_secthead_rel;
@ -84,6 +91,9 @@ typedef struct {
func_map_reloc_info_to_type map_reloc_info_to_type;
func_write_reloc write_reloc;
func_write_proghead write_proghead;
const elf_machine_ssym *ssyms; /* array of "special" syms */
const size_t num_ssyms; /* size of array */
} elf_machine_handler;
#endif /* ELF_MACHINE_H_INCLUDED */

View file

@ -62,6 +62,8 @@ typedef struct yasm_objfmt_elf {
yasm_object *object;
yasm_symtab *symtab;
/*@dependent@*/ yasm_arch *arch;
yasm_symrec *dotdotsym; /* ..sym symbol */
} yasm_objfmt_elf;
typedef struct {
@ -154,7 +156,7 @@ elf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a)
objfmt_elf->object = object;
objfmt_elf->symtab = yasm_object_get_symtab(object);
objfmt_elf->arch = a;
if (!elf_set_arch(a)) {
if (!elf_set_arch(a, objfmt_elf->symtab)) {
yasm_xfree(objfmt_elf);
return NULL;
}
@ -166,14 +168,18 @@ elf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a)
objfmt_elf->elf_symtab = elf_symtab_create();
/* FIXME: misuse of NULL bytecode here; it works, but only barely. */
filesym = yasm_symtab_define_label(yasm_object_get_symtab(object), ".file",
NULL, 0, 0);
filesym = yasm_symtab_define_label(objfmt_elf->symtab, ".file", NULL, 0,
0);
entry = elf_symtab_entry_create(
elf_strtab_append_str(objfmt_elf->strtab, in_filename), filesym);
yasm_symrec_add_data(filesym, &elf_symrec_data, entry);
elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL, 0);
elf_symtab_append_entry(objfmt_elf->elf_symtab, entry);
/* FIXME: misuse of NULL bytecode */
objfmt_elf->dotdotsym = yasm_symtab_define_label(objfmt_elf->symtab,
"..sym", NULL, 1, 0);
return (yasm_objfmt *)objfmt_elf;
}
@ -204,15 +210,15 @@ elf_objfmt_output_align(FILE *f, unsigned int align)
static int
elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
unsigned char *buf, size_t destsize, size_t valsize,
int rel, int warn, void *d)
int warn, void *d)
{
elf_reloc_entry *reloc;
elf_objfmt_output_info *info = d;
yasm_intnum *zero;
int retval;
reloc = elf_reloc_entry_create(sym,
yasm_intnum_create_uint(bc->offset), rel, valsize);
reloc = elf_reloc_entry_create(sym, NULL,
yasm_intnum_create_uint(bc->offset), 0, valsize);
if (reloc == NULL) {
yasm__error(bc->line, N_("elf: invalid relocation size"));
return 1;
@ -224,7 +230,7 @@ elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc,
zero = yasm_intnum_create_uint(0);
elf_handle_reloc_addend(zero, reloc);
retval = yasm_arch_intnum_tobytes(info->objfmt_elf->arch, zero, buf,
destsize, valsize, 0, bc, rel, warn,
destsize, valsize, 0, bc, warn,
bc->line);
yasm_intnum_destroy(zero);
return retval;
@ -241,6 +247,8 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
/*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
/*@dependent@*/ /*@null@*/ yasm_symrec *sym;
/*@null@*/ elf_reloc_entry *reloc = NULL;
/*@null@*/ yasm_expr *wrt_expr;
/*@dependent@*/ /*@null@*/ yasm_symrec *wrt = NULL;
if (info == NULL)
yasm_internal_error("null info struct");
@ -257,13 +265,32 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
(unsigned int)shift, warn, bc->line);
}
/* Check for a WRT relocation */
wrt_expr = yasm_expr_extract_wrt(ep);
if (wrt_expr) {
wrt = yasm_expr_extract_symrec(&wrt_expr, 0,
yasm_common_calc_bc_dist);
yasm_expr_destroy(wrt_expr);
if (!wrt) {
yasm__error(bc->line, N_("WRT expression too complex"));
return 1;
}
}
/* Handle integer expressions, with relocation if necessary */
sym = yasm_expr_extract_symrec(ep, 1, yasm_common_calc_bc_dist);
sym = yasm_expr_extract_symrec(ep,
!(wrt == info->objfmt_elf->dotdotsym ||
(wrt && elf_is_wrt_sym_relative(wrt))),
yasm_common_calc_bc_dist);
if (sym) {
yasm_sym_vis vis;
vis = yasm_symrec_get_visibility(sym);
if (!(vis & (YASM_SYM_COMMON|YASM_SYM_EXTERN)))
if (wrt == info->objfmt_elf->dotdotsym)
wrt = NULL;
else if (wrt && elf_is_wrt_sym_relative(wrt))
;
else if (!(vis & (YASM_SYM_COMMON|YASM_SYM_EXTERN)))
{
yasm_bytecode *label_precbc;
/* Local symbols need relocation to their section's start */
@ -290,10 +317,10 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
*ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
}
reloc = elf_reloc_entry_create(sym,
reloc = elf_reloc_entry_create(sym, wrt,
yasm_intnum_create_uint(bc->offset + offset), rel, valsize);
if (reloc == NULL) {
yasm__error(bc->line, N_("elf: invalid relocation size"));
yasm__error(bc->line, N_("elf: invalid relocation (WRT or size)"));
return 1;
}
/* allocate .rel[a] sections on a need-basis */
@ -302,12 +329,20 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
}
intn = yasm_expr_get_intnum(ep, NULL);
if (intn && reloc)
elf_handle_reloc_addend(intn, reloc);
if (intn)
if (intn) {
if (rel) {
int retval = yasm_arch_intnum_fixup_rel(info->objfmt_elf->arch,
intn, valsize, bc,
bc->line);
if (retval)
return retval;
}
if (reloc)
elf_handle_reloc_addend(intn, reloc);
return yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf,
destsize, valsize, shift, bc, rel,
warn, bc->line);
destsize, valsize, shift, bc, warn,
bc->line);
}
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {

View file

@ -26,7 +26,7 @@
*/
#include <util.h>
/*@unused@*/ RCSID("$Id:$");
/*@unused@*/ RCSID("$Id$");
#define YASM_LIB_INTERNAL
#define YASM_EXPR_INTERNAL
@ -35,9 +35,23 @@
#include "elf.h"
#include "elf-machine.h"
enum ssym_index {
SSYM_GOTPCREL = 0,
SSYM_GOT,
SSYM_PLT
};
static int
elf_x86_amd64_accepts_reloc_size(size_t val)
elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt, yasm_symrec **ssyms)
{
if (wrt) {
if ((wrt == ssyms[SSYM_GOTPCREL] && val == 32)
|| (wrt == ssyms[SSYM_GOT] && val == 32)
|| (wrt == ssyms[SSYM_PLT] && val == 32))
return 1;
else
return 0;
}
return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0);
}
@ -126,9 +140,19 @@ elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc)
}
static unsigned int
elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc)
elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc,
yasm_symrec **ssyms)
{
if (reloc->rtype_rel) {
if (reloc->wrt) {
if (reloc->wrt == ssyms[SSYM_GOTPCREL] && reloc->valsize == 32)
return (unsigned char) R_X86_64_GOTPCREL;
else if (reloc->wrt == ssyms[SSYM_GOT] && reloc->valsize == 32)
return (unsigned char) R_X86_64_GOT32;
else if (reloc->wrt == ssyms[SSYM_PLT] && reloc->valsize == 32)
return (unsigned char) R_X86_64_PLT32;
else
yasm_internal_error(N_("Unsupported WRT"));
} else if (reloc->rtype_rel) {
switch (reloc->valsize) {
case 8: return (unsigned char) R_X86_64_PC8;
case 16: return (unsigned char) R_X86_64_PC16;
@ -190,16 +214,24 @@ elf_x86_amd64_write_proghead(unsigned char **bufpp,
*bufpp = bufp;
}
static elf_machine_ssym elf_x86_amd64_ssyms[] = {
{"..gotpcrel", 1},
{"..got", 1},
{"..plt", 0}
};
const elf_machine_handler
elf_machine_handler_x86_amd64 = {
"x86", "amd64", ".rela",
SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE,
elf_x86_amd64_accepts_reloc_size,
elf_x86_amd64_accepts_reloc,
elf_x86_amd64_write_symtab_entry,
elf_x86_amd64_write_secthead,
elf_x86_amd64_write_secthead_rel,
elf_x86_amd64_handle_reloc_addend,
elf_x86_amd64_map_reloc_info_to_type,
elf_x86_amd64_write_reloc,
elf_x86_amd64_write_proghead
elf_x86_amd64_write_proghead,
elf_x86_amd64_ssyms,
sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0])
};

View file

@ -26,7 +26,7 @@
*/
#include <util.h>
/*@unused@*/ RCSID("$Id:$");
/*@unused@*/ RCSID("$Id$");
#define YASM_LIB_INTERNAL
#define YASM_EXPR_INTERNAL
@ -35,9 +35,25 @@
#include "elf.h"
#include "elf-machine.h"
enum ssym_index {
SSYM_GOTPC = 0,
SSYM_GOTOFF,
SSYM_GOT,
SSYM_PLT
};
static int
elf_x86_x86_accepts_reloc_size(size_t val)
elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt, yasm_symrec **ssyms)
{
if (wrt) {
if ((wrt == ssyms[SSYM_GOTPC] && val == 32)
|| (wrt == ssyms[SSYM_GOTOFF] && val == 32)
|| (wrt == ssyms[SSYM_GOT] && val == 32)
|| (wrt == ssyms[SSYM_PLT] && val == 32))
return 1;
else
return 0;
}
return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0);
}
@ -117,9 +133,21 @@ elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc)
}
static unsigned int
elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc)
elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc,
yasm_symrec **ssyms)
{
if (reloc->rtype_rel) {
if (reloc->wrt) {
if (reloc->wrt == ssyms[SSYM_GOTPC] && reloc->valsize == 32)
return (unsigned char) R_386_GOTPC;
else if (reloc->wrt == ssyms[SSYM_GOTOFF] && reloc->valsize == 32)
return (unsigned char) R_386_GOTOFF;
else if (reloc->wrt == ssyms[SSYM_GOT] && reloc->valsize == 32)
return (unsigned char) R_386_GOT32;
else if (reloc->wrt == ssyms[SSYM_PLT] && reloc->valsize == 32)
return (unsigned char) R_386_PLT32;
else
yasm_internal_error(N_("Unsupported WRT"));
} else if (reloc->rtype_rel) {
switch (reloc->valsize) {
case 8: return (unsigned char) R_386_PC8;
case 16: return (unsigned char) R_386_PC16;
@ -175,16 +203,25 @@ elf_x86_x86_write_proghead(unsigned char **bufpp,
*bufpp = bufp;
}
static elf_machine_ssym elf_x86_x86_ssyms[] = {
{"..gotpc", 0},
{"..gotoff", 0},
{"..got", 1},
{"..plt", 0}
};
const elf_machine_handler
elf_machine_handler_x86_x86 = {
"x86", "x86", ".rel",
SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE,
elf_x86_x86_accepts_reloc_size,
elf_x86_x86_accepts_reloc,
elf_x86_x86_write_symtab_entry,
elf_x86_x86_write_secthead,
elf_x86_x86_write_secthead_rel,
elf_x86_x86_handle_reloc_addend,
elf_x86_x86_map_reloc_info_to_type,
elf_x86_x86_write_reloc,
elf_x86_x86_write_proghead
elf_x86_x86_write_proghead,
elf_x86_x86_ssyms,
sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0])
};

View file

@ -63,9 +63,10 @@ static const elf_machine_handler *elf_machine_handlers[] =
};
static const elf_machine_handler elf_null_machine = {0};
static elf_machine_handler const *elf_march = &elf_null_machine;
static yasm_symrec **elf_ssyms;
int
elf_set_arch(yasm_arch *arch)
elf_set_arch(yasm_arch *arch, yasm_symtab *symtab)
{
const char *machine = yasm_arch_get_machine(arch);
int i;
@ -78,23 +79,50 @@ elf_set_arch(yasm_arch *arch)
if (yasm__strcasecmp(machine, elf_march->machine)==0)
break;
}
if (elf_march && elf_march->num_ssyms > 0)
{
/* Allocate "special" syms */
elf_ssyms =
yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *));
for (i=0; (unsigned int)i<elf_march->num_ssyms; i++)
{
/* FIXME: misuse of NULL bytecode */
elf_ssyms[i] = yasm_symtab_define_label(symtab,
elf_march->ssyms[i].name,
NULL, 1, 0);
}
}
return elf_march != NULL;
}
/* reloc functions */
int
elf_is_wrt_sym_relative(yasm_symrec *wrt)
{
int i;
for (i=0; (unsigned int)i<elf_march->num_ssyms; i++) {
if (elf_ssyms[i] == wrt)
return elf_march->ssyms[i].sym_rel;
}
return 0;
}
/* takes ownership of addr */
elf_reloc_entry *
elf_reloc_entry_create(yasm_symrec *sym,
yasm_symrec *wrt,
yasm_intnum *addr,
int rel,
size_t valsize)
{
elf_reloc_entry *entry;
if (!elf_march->accepts_reloc_size)
if (!elf_march->accepts_reloc)
yasm_internal_error(N_("Unsupported machine for ELF output"));
if (!elf_march->accepts_reloc_size(valsize))
if (!elf_march->accepts_reloc(valsize, wrt, elf_ssyms))
{
if (addr)
yasm_intnum_destroy(addr);
@ -110,6 +138,7 @@ elf_reloc_entry_create(yasm_symrec *sym,
entry->rtype_rel = rel;
entry->valsize = valsize;
entry->addend = NULL;
entry->wrt = wrt;
return entry;
}
@ -670,7 +699,7 @@ elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect,
vis = yasm_symrec_get_visibility(reloc->reloc.sym);
if (!elf_march->map_reloc_info_to_type)
yasm_internal_error(N_("Unsupported arch/machine for elf output"));
r_type = elf_march->map_reloc_info_to_type(reloc);
r_type = elf_march->map_reloc_info_to_type(reloc, elf_ssyms);
bufp = buf;
if (!elf_march->write_reloc || !elf_march->reloc_entry_size)

View file

@ -354,6 +354,7 @@ struct elf_reloc_entry {
int rtype_rel;
size_t valsize;
yasm_intnum *addend;
/*@null@*/ yasm_symrec *wrt;
};
STAILQ_HEAD(elf_strtab_head, elf_strtab_entry);
@ -384,10 +385,12 @@ extern const yasm_assoc_data_callback elf_section_data;
extern const yasm_assoc_data_callback elf_symrec_data;
int elf_set_arch(struct yasm_arch *arch);
int elf_set_arch(struct yasm_arch *arch, yasm_symtab *symtab);
/* reloc functions */
int elf_is_wrt_sym_relative(yasm_symrec *wrt);
elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym,
/*@null@*/ yasm_symrec *wrt,
yasm_intnum *addr,
int rel,
size_t valsize);

View file

@ -6,6 +6,9 @@ EXTRA_DIST += modules/objfmts/elf/tests/elf_test.sh
EXTRA_DIST += modules/objfmts/elf/tests/elfsectalign.asm
EXTRA_DIST += modules/objfmts/elf/tests/elfsectalign.hex
EXTRA_DIST += modules/objfmts/elf/tests/elfsectalign.errwarn
EXTRA_DIST += modules/objfmts/elf/tests/elfso.asm
EXTRA_DIST += modules/objfmts/elf/tests/elfso.hex
EXTRA_DIST += modules/objfmts/elf/tests/elfso.errwarn
EXTRA_DIST += modules/objfmts/elf/tests/elftest.c
EXTRA_DIST += modules/objfmts/elf/tests/elftest.asm
EXTRA_DIST += modules/objfmts/elf/tests/elftest.hex

View file

@ -6,3 +6,6 @@ EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf_amd64_test.sh
EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf-rip.asm
EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf-rip.hex
EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf-rip.errwarn
EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.asm
EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.hex
EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.errwarn

View file

@ -82,15 +82,15 @@
00
8b
05
fa
ff
ff
ff
00
00
00
00
e8
fb
ff
ff
ff
00
00
00
00
00
00
00
@ -134,14 +134,14 @@ ff
00
00
00
02
00
00
00
00
00
00
00
fc
ff
ff
ff
ff
ff
ff
ff
19
00
00
@ -158,14 +158,14 @@ ff
00
00
00
01
00
00
00
00
00
00
00
fc
ff
ff
ff
ff
ff
ff
ff
00
2e
74

View file

@ -0,0 +1,90 @@
; This code is UNTESTED, and almost certainly DOES NOT WORK!
; Do NOT use this as an example of how to write AMD64 shared libraries!
; This code is simply to test the AMD64 ELF WRT relocations.
; This file should test the following:
; [1] Define and export a global text-section symbol
; [2] Define and export a global data-section symbol
; [3] Define and export a global BSS-section symbol
; [4] Define a non-global text-section symbol
; [5] Define a non-global data-section symbol
; [6] Define a non-global BSS-section symbol
; [7] Define a COMMON symbol
; [8] Define a NASM local label
; [9] Reference a NASM local label
; [10] Import an external symbol
; [11] Make a PC-relative call to an external symbol
; [12] Reference a text-section symbol in the text section
; [13] Reference a data-section symbol in the text section
; [14] Reference a BSS-section symbol in the text section
; [15] Reference a text-section symbol in the data section
; [16] Reference a data-section symbol in the data section
; [17] Reference a BSS-section symbol in the data section
BITS 64
GLOBAL lrotate:function ; [1]
GLOBAL greet:function ; [1]
GLOBAL asmstr:data asmstr.end-asmstr ; [2]
GLOBAL textptr:data 4 ; [2]
GLOBAL selfptr:data 4 ; [2]
GLOBAL integer:data 4 ; [3]
EXTERN printf ; [10]
COMMON commvar 4:4 ; [7]
EXTERN _GLOBAL_OFFSET_TABLE_
SECTION .text
; prototype: long lrotate(long x, int num);
lrotate: ; [1]
push rbp
mov rbp,rsp
mov rax,[rbp+8]
mov rcx,[rbp+12]
.label rol rax,1 ; [4] [8]
loop .label ; [9] [12]
mov rsp,rbp
pop rbp
ret
; prototype: void greet(void);
greet push rbx ; we'll use RBX for GOT, so save it
mov rbx,[integer wrt ..gotpcrel wrt rip]
mov rax,[rbx] ; [14]
inc rax
mov rbx,[_GLOBAL_OFFSET_TABLE_ wrt ..gotpcrel wrt rip]
mov [rbx+localint wrt ..got],eax ; [14]
mov rax,[rbx+commvar wrt ..got]
push qword [rax]
mov rax,[rbx+localptr wrt ..got] ; [13]
push qword [rax]
mov rax,[rbx+integer wrt ..got] ; [1] [14]
push qword [rax]
lea rax,[rbx+printfstr wrt ..got]
push rax ; [13]
call printf wrt ..plt ; [11]
add rsp,16
pop rbx
ret
SECTION .data
; a string
asmstr db 'hello, world', 0 ; [2]
.end
; a string for Printf
printfstr db "integer==%d, localint==%d, commvar=%d"
db 10, 0
; some pointers
localptr dd localint ; [5] [17]
textptr dd greet wrt ..sym ; [15]
selfptr dd selfptr wrt ..sym ; [16]
SECTION .bss
; an integer
integer resd 1 ; [3]
; a local integer
localint resd 1 ; [6]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,97 @@
; test source file for assembling to ELF shared library
; build with:
; nasm -f elf elfso.asm
; ld -shared -o elfso.so elfso.o
; test with:
; gcc -o elfso elftest.c ./elfso.so
; ./elfso
; (assuming your gcc is ELF, and you're running bash)
; This file should test the following:
; [1] Define and export a global text-section symbol
; [2] Define and export a global data-section symbol
; [3] Define and export a global BSS-section symbol
; [4] Define a non-global text-section symbol
; [5] Define a non-global data-section symbol
; [6] Define a non-global BSS-section symbol
; [7] Define a COMMON symbol
; [8] Define a NASM local label
; [9] Reference a NASM local label
; [10] Import an external symbol
; [11] Make a PC-relative call to an external symbol
; [12] Reference a text-section symbol in the text section
; [13] Reference a data-section symbol in the text section
; [14] Reference a BSS-section symbol in the text section
; [15] Reference a text-section symbol in the data section
; [16] Reference a data-section symbol in the data section
; [17] Reference a BSS-section symbol in the data section
BITS 32
GLOBAL lrotate:function ; [1]
GLOBAL greet:function ; [1]
GLOBAL asmstr:data asmstr.end-asmstr ; [2]
GLOBAL textptr:data 4 ; [2]
GLOBAL selfptr:data 4 ; [2]
GLOBAL integer:data 4 ; [3]
EXTERN printf ; [10]
COMMON commvar 4:4 ; [7]
EXTERN _GLOBAL_OFFSET_TABLE_
SECTION .text
; prototype: long lrotate(long x, int num);
lrotate: ; [1]
push ebp
mov ebp,esp
mov eax,[ebp+8]
mov ecx,[ebp+12]
.label rol eax,1 ; [4] [8]
loop .label ; [9] [12]
mov esp,ebp
pop ebp
ret
; prototype: void greet(void);
greet push ebx ; we'll use EBX for GOT, so save it
call .getgot
.getgot: pop ebx
add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - .getgot wrt ..gotpc
mov eax,[ebx+integer wrt ..got] ; [14]
mov eax,[eax]
inc eax
mov [ebx+localint wrt ..gotoff],eax ; [14]
mov eax,[ebx+commvar wrt ..got]
push dword [eax]
mov eax,[ebx+localptr wrt ..gotoff] ; [13]
push dword [eax]
mov eax,[ebx+integer wrt ..got] ; [1] [14]
push dword [eax]
lea eax,[ebx+printfstr wrt ..gotoff]
push eax ; [13]
call printf wrt ..plt ; [11]
add esp,16
pop ebx
ret
SECTION .data
; a string
asmstr db 'hello, world', 0 ; [2]
.end
; a string for Printf
printfstr db "integer==%d, localint==%d, commvar=%d"
db 10, 0
; some pointers
localptr dd localint ; [5] [17]
textptr dd greet wrt ..sym ; [15]
selfptr dd selfptr wrt ..sym ; [16]
SECTION .bss
; an integer
integer resd 1 ; [3]
; a local integer
localint resd 1 ; [6]

View file

File diff suppressed because it is too large Load diff

View file

@ -206,7 +206,7 @@ xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
{
/*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d;
yasm_objfmt_xdf *objfmt_xdf;
/*@dependent@*/ /*@null@*/ const yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ yasm_intnum *intn;
/*@dependent@*/ /*@null@*/ const yasm_floatnum *flt;
/*@dependent@*/ /*@null@*/ yasm_symrec *sym;
yasm_expr *shr_expr;
@ -284,10 +284,16 @@ xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize,
yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
}
intn = yasm_expr_get_intnum(ep, NULL);
if (intn)
if (intn) {
if (rel) {
int retval = yasm_arch_intnum_fixup_rel(objfmt_xdf->arch, intn,
valsize, bc, bc->line);
if (retval)
return retval;
}
return yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize,
valsize, shift, bc, rel, warn,
bc->line);
valsize, shift, bc, warn, bc->line);
}
/* Check for complex float expressions */
if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) {

View file

@ -110,6 +110,8 @@ static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name,
%type <insn_operands> operands
%type <insn_operand> operand
%left ':'
%left WRT
%left '|'
%left '^'
%left '&'
@ -117,8 +119,7 @@ static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name,
%left '-' '+'
%left '*' '/' SIGNDIV '%' SIGNMOD
%nonassoc UNARYOP
%nonassoc SEG WRT
%left ':'
%nonassoc SEG
%%
input: /* empty */