Add Win32 object format (untested, but compared against NASM output).

svn path=/trunk/yasm/; revision=884
0.2
Peter Johnson 22 years ago
parent dd1d356936
commit 6960b31329
  1. 4
      modules/objfmts/Makefile.inc
  2. 273
      modules/objfmts/coff/coff-objfmt.c
  3. 14
      modules/objfmts/win32/Makefile.inc
  4. 11
      modules/objfmts/win32/tests/Makefile.inc
  5. 82
      modules/objfmts/win32/tests/win32test.asm
  6. 34
      modules/objfmts/win32/tests/win32test.c
  7. 0
      modules/objfmts/win32/tests/win32test.errwarn
  8. 660
      modules/objfmts/win32/tests/win32test.hex

@ -3,8 +3,10 @@
EXTRA_DIST += \
modules/objfmts/dbg/Makefile.inc \
modules/objfmts/bin/Makefile.inc \
modules/objfmts/coff/Makefile.inc
modules/objfmts/coff/Makefile.inc \
modules/objfmts/win32/Makefile.inc
include modules/objfmts/dbg/Makefile.inc
include modules/objfmts/bin/Makefile.inc
include modules/objfmts/coff/Makefile.inc
include modules/objfmts/win32/Makefile.inc

@ -40,7 +40,7 @@
* with VMA=0. Who's right? This is #defined as changing this setting affects
* several places in the code.
*/
#define COFF_SET_VMA 1
#define COFF_SET_VMA (!win32)
#define COFF_I386MAGIC 0x14C
@ -60,16 +60,26 @@ typedef struct coff_reloc {
} type; /* type of relocation */
} coff_reloc;
typedef enum coff_section_data_flags {
COFF_STYP_TEXT = 0x0020,
COFF_STYP_DATA = 0x0040,
COFF_STYP_BSS = 0x0080
} coff_section_data_flags;
#define COFF_STYP_TEXT 0x00000020UL
#define COFF_STYP_DATA 0x00000040UL
#define COFF_STYP_BSS 0x00000080UL
#define COFF_STYP_INFO 0x00000200UL
#define COFF_STYP_STD_MASK 0x000003FFUL
#define COFF_STYP_ALIGN_MASK 0x00F00000UL
#define COFF_STYP_ALIGN_SHIFT 20
#define COFF_STYP_DISCARD 0x02000000UL
#define COFF_STYP_NOCACHE 0x04000000UL
#define COFF_STYP_NOPAGE 0x08000000UL
#define COFF_STYP_SHARED 0x10000000UL
#define COFF_STYP_EXECUTE 0x20000000UL
#define COFF_STYP_READ 0x40000000UL
#define COFF_STYP_WRITE 0x80000000UL
#define COFF_STYP_WIN32_MASK 0xFE000000UL
typedef struct coff_section_data {
/*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
unsigned int scnum; /* section number (1=first section) */
coff_section_data_flags flags;
unsigned long flags; /* section flags (see COFF_STYP_* above) */
unsigned long addr; /* starting memory address (first section -> 0) */
unsigned long scnptr; /* file ptr to raw data */
unsigned long size; /* size of raw data (section data) in bytes */
@ -150,6 +160,9 @@ static coff_symtab_head coff_symtab; /* symbol table of indexed syms */
yasm_objfmt yasm_coff_LTX_objfmt;
static /*@dependent@*/ yasm_arch *cur_arch;
/* Set nonzero for win32 output. */
static int win32;
static /*@dependent@*/ coff_symtab_entry *
coff_objfmt_symtab_append(yasm_symrec *sym, coff_symrec_sclass sclass,
@ -192,7 +205,7 @@ coff_objfmt_append_local_sym(yasm_symrec *sym, /*@unused@*/ /*@null@*/ void *d)
}
static void
coff_objfmt_initialize(const char *in_filename,
coff_common_initialize(const char *in_filename,
/*@unused@*/ const char *obj_filename,
/*@unused@*/ yasm_dbgfmt *df, yasm_arch *a)
{
@ -220,6 +233,22 @@ coff_objfmt_initialize(const char *in_filename,
STAILQ_INSERT_TAIL(&coff_symtab, entry, link);
}
static void
coff_objfmt_initialize(const char *in_filename, const char *obj_filename,
yasm_dbgfmt *df, yasm_arch *a)
{
win32 = 0;
coff_common_initialize(in_filename, obj_filename, df, a);
}
static void
win32_objfmt_initialize(const char *in_filename, const char *obj_filename,
yasm_dbgfmt *df, yasm_arch *a)
{
win32 = 1;
coff_common_initialize(in_filename, obj_filename, df, a);
}
static int
coff_objfmt_set_section_addr(yasm_section *sect, /*@null@*/ void *d)
{
@ -283,15 +312,17 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp,
reloc->sym = sym;
vis = yasm_symrec_get_visibility(sym);
if (vis & YASM_SYM_COMMON) {
/*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
/* COMMON symbols have their length added in */
csymd = yasm_symrec_get_of_data(sym);
assert(csymd != NULL);
*ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep),
yasm_expr_expr(yasm_expr_copy(csymd->size)),
csymd->size->line);
*ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
/* In standard COFF, COMMON symbols have their length added in */
if (!win32) {
/*@dependent@*/ /*@null@*/ coff_symrec_data *csymd;
csymd = yasm_symrec_get_of_data(sym);
assert(csymd != NULL);
*ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep),
yasm_expr_expr(yasm_expr_copy(csymd->size)),
csymd->size->line);
*ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
}
} else if (!(vis & YASM_SYM_EXTERN)) {
/* Local symbols need relocation to their section's start */
if (yasm_symrec_get_label(sym, &label_sect, &label_precbc)) {
@ -308,11 +339,22 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char **bufp,
if (rel) {
reloc->type = COFF_RELOC_REL32;
/* Need to reference to start of section, so add $$ in. */
*ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep),
yasm_expr_sym(yasm_symrec_define_label("$$", info->sect, NULL,
0, (*ep)->line)),
(*ep)->line);
/* For standard COFF, need to reference to start of section, so add
* $$ in.
* For Win32 COFF, need to reference to next bytecode, so add '$'
* (really $+$.len) in.
*/
if (win32)
*ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep),
yasm_expr_sym(yasm_symrec_define_label("$", info->sect, bc,
0, (*ep)->line)),
(*ep)->line);
else
*ep = yasm_expr_new(YASM_EXPR_ADD, yasm_expr_expr(*ep),
yasm_expr_sym(yasm_symrec_define_label("$$", info->sect,
NULL, 0,
(*ep)->line)),
(*ep)->line);
*ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist);
} else
reloc->type = COFF_RELOC_ADDR32;
@ -401,7 +443,7 @@ coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
csd->addr = info->addr;
if (csd->flags == COFF_STYP_BSS) {
if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
/*@null@*/ yasm_bytecode *last =
yasm_bcs_last(yasm_section_get_bytecodes(sect));
@ -747,42 +789,170 @@ coff_objfmt_sections_switch(yasm_sectionhead *headp,
yasm_valparam *vp = yasm_vps_first(valparams);
yasm_section *retval;
int isnew;
coff_section_data_flags flags;
unsigned long flags;
int flags_override = 0;
char *sectname;
int resonly = 0;
static const struct {
const char *name;
unsigned long stdflags; /* if 0, win32 only qualifier */
unsigned long win32flags;
/* Mode: 0 => clear specified bits
* 1 => set specified bits
* 2 => clear all bits, then set specified bits
*/
int mode;
} flagquals[] = {
{ "code", COFF_STYP_TEXT, COFF_STYP_EXECUTE | COFF_STYP_READ, 2 },
{ "text", COFF_STYP_TEXT, COFF_STYP_EXECUTE | COFF_STYP_READ, 2 },
{ "data", COFF_STYP_DATA, COFF_STYP_READ | COFF_STYP_WRITE, 2 },
{ "bss", COFF_STYP_BSS, COFF_STYP_READ | COFF_STYP_WRITE, 2 },
{ "info", COFF_STYP_INFO, COFF_STYP_DISCARD | COFF_STYP_READ, 2 },
{ "discard", 0, COFF_STYP_DISCARD, 1 },
{ "nodiscard", 0, COFF_STYP_DISCARD, 0 },
{ "cache", 0, COFF_STYP_NOCACHE, 0 },
{ "nocache", 0, COFF_STYP_NOCACHE, 1 },
{ "page", 0, COFF_STYP_NOPAGE, 0 },
{ "nopage", 0, COFF_STYP_NOPAGE, 1 },
{ "share", 0, COFF_STYP_SHARED, 1 },
{ "noshare", 0, COFF_STYP_SHARED, 0 },
{ "execute", 0, COFF_STYP_EXECUTE, 1 },
{ "noexecute", 0, COFF_STYP_EXECUTE, 0 },
{ "read", 0, COFF_STYP_READ, 1 },
{ "noread", 0, COFF_STYP_READ, 0 },
{ "write", 0, COFF_STYP_WRITE, 1 },
{ "nowrite", 0, COFF_STYP_WRITE, 0 },
};
if (!vp || vp->param || !vp->val)
return NULL;
sectname = vp->val;
if (strlen(sectname) > 8) {
/* TODO: win32 format supports >8 character section names in object
* files via "/nnnn" (where nnnn is decimal offset into string table).
*/
yasm__warning(YASM_WARN_GENERAL, lindex,
N_("COFF section names limited to 8 characters: truncating"));
sectname[8] = '\0';
}
if (strcmp(sectname, ".data") == 0)
if (strcmp(sectname, ".data") == 0) {
flags = COFF_STYP_DATA;
else if (strcmp(sectname, ".bss") == 0) {
if (win32)
flags |= COFF_STYP_READ | COFF_STYP_WRITE |
(3<<COFF_STYP_ALIGN_SHIFT); /* align=4 */
} else if (strcmp(sectname, ".bss") == 0) {
flags = COFF_STYP_BSS;
if (win32)
flags |= COFF_STYP_READ | COFF_STYP_WRITE |
(3<<COFF_STYP_ALIGN_SHIFT); /* align=4 */
resonly = 1;
} else
} else if (strcmp(sectname, ".text") == 0) {
flags = COFF_STYP_TEXT;
if (win32)
flags |= COFF_STYP_EXECUTE | COFF_STYP_READ |
(5<<COFF_STYP_ALIGN_SHIFT); /* align=16 */
} else if (strcmp(sectname, ".rdata") == 0) {
flags = COFF_STYP_DATA;
if (win32)
flags |= COFF_STYP_READ | (4<<COFF_STYP_ALIGN_SHIFT); /* align=8 */
else
yasm__warning(YASM_WARN_GENERAL, lindex,
N_("Standard COFF does not support read-only data sections"));
} else {
/* Default to code */
flags = COFF_STYP_TEXT;
if (win32)
flags |= COFF_STYP_EXECUTE | COFF_STYP_READ;
}
while ((vp = yasm_vps_next(vp))) {
if (yasm__strcasecmp(vp->val, "code") == 0 ||
yasm__strcasecmp(vp->val, "text") == 0) {
flags = COFF_STYP_TEXT;
flags_override = 1;
} else if (yasm__strcasecmp(vp->val, "data") == 0) {
flags = COFF_STYP_DATA;
flags_override = 1;
} else if (yasm__strcasecmp(vp->val, "bss") == 0) {
flags = COFF_STYP_BSS;
flags_override = 1;
resonly = 1;
size_t i;
int match, win32warn;
win32warn = 0;
match = 0;
for (i=0; i<NELEMS(flagquals) && !match; i++) {
if (yasm__strcasecmp(vp->val, flagquals[i].name) == 0) {
if (!win32 && flagquals[i].stdflags == 0)
win32warn = 1;
else switch (flagquals[i].mode) {
case 0:
flags &= ~flagquals[i].stdflags;
if (win32)
flags &= ~flagquals[i].win32flags;
break;
case 1:
flags |= flagquals[i].stdflags;
if (win32)
flags |= flagquals[i].win32flags;
break;
case 2:
flags &= ~COFF_STYP_STD_MASK;
flags |= flagquals[i].stdflags;
if (win32) {
flags &= ~COFF_STYP_WIN32_MASK;
flags |= flagquals[i].win32flags;
}
break;
}
flags_override = 1;
match = 1;
}
}
if (match)
;
else if (yasm__strcasecmp(vp->val, "align") == 0 && vp->param) {
if (win32) {
/*@dependent@*/ /*@null@*/ const yasm_intnum *align;
unsigned long bitcnt;
unsigned long addralign;
align = yasm_expr_get_intnum(&vp->param, NULL);
if (!align) {
yasm__error(lindex,
N_("argument to `%s' is not a power of two"),
vp->val);
return NULL;
}
addralign = yasm_intnum_get_uint(align);
/* Check to see if alignment is a power of two.
* This can be checked by seeing if only one bit is set.
*/
BitCount(bitcnt, addralign);
if (bitcnt > 1) {
yasm__error(lindex,
N_("argument to `%s' is not a power of two"),
vp->val);
return NULL;
}
/* Check to see if alignment is supported size */
if (addralign > 8192) {
yasm__error(lindex,
N_("Win32 does not support alignments > 8192"));
return NULL;
}
/* Convert alignment into flags setting */
flags &= ~COFF_STYP_ALIGN_MASK;
while (addralign != 0) {
flags += 1<<COFF_STYP_ALIGN_SHIFT;
addralign >>= 1;
}
} else
win32warn = 1;
} else
yasm__warning(YASM_WARN_GENERAL, lindex,
N_("Unrecognized qualifier `%s'"), vp->val);
if (win32warn)
yasm__warning(YASM_WARN_GENERAL, lindex,
N_("Standard COFF does not support qualifier `%s'"), vp->val);
}
retval = yasm_sections_switch_general(headp, sectname, 0, resonly, &isnew,
@ -839,7 +1009,7 @@ coff_objfmt_section_data_print(FILE *f, int indent_level, void *data)
yasm_symrec_print(f, indent_level+1, csd->sym);
fprintf(f, "%*sscnum=%d\n", indent_level, "", csd->scnum);
fprintf(f, "%*sflags=", indent_level, "");
switch (csd->flags) {
switch (csd->flags & COFF_STYP_STD_MASK) {
case COFF_STYP_TEXT:
fprintf(f, "TEXT");
break;
@ -960,3 +1130,28 @@ yasm_objfmt yasm_coff_LTX_objfmt = {
NULL /*coff_objfmt_bc_objfmt_data_delete*/,
NULL /*coff_objfmt_bc_objfmt_data_print*/
};
/* Define objfmt structure -- see objfmt.h for details */
yasm_objfmt yasm_win32_LTX_objfmt = {
"Win32",
"win32",
"obj",
".text",
32,
coff_objfmt_dbgfmt_keywords,
"null",
win32_objfmt_initialize,
coff_objfmt_output,
coff_objfmt_cleanup,
coff_objfmt_sections_switch,
coff_objfmt_section_data_delete,
coff_objfmt_section_data_print,
coff_objfmt_extglob_declare,
coff_objfmt_extglob_declare,
coff_objfmt_common_declare,
coff_objfmt_symrec_data_delete,
coff_objfmt_symrec_data_print,
coff_objfmt_directive,
NULL /*coff_objfmt_bc_objfmt_data_delete*/,
NULL /*coff_objfmt_bc_objfmt_data_print*/
};

@ -0,0 +1,14 @@
# $IdPath$
lib_LTLIBRARIES += yasm-win32.la
yasm_win32_la_SOURCES = \
modules/objfmts/coff/coff-objfmt.c
yasm_win32_la_LDFLAGS = -module -avoid-version -no-undefined
yasm_win32_la_LIBADD = libyasm.la
YASM_MODULES += -dlopen yasm-win32.la
EXTRA_DIST += \
modules/objfmts/win32/tests/Makefile.inc
include modules/objfmts/win32/tests/Makefile.inc

@ -0,0 +1,11 @@
# $IdPath$
TESTS += \
modules/objfmts/win32/tests/win32_test.sh
EXTRA_DIST += \
modules/objfmts/win32/tests/win32_test.sh \
modules/objfmts/win32/tests/win32test.c \
modules/objfmts/win32/tests/win32test.asm \
modules/objfmts/win32/tests/win32test.hex \
modules/objfmts/win32/tests/win32test.errwarn

@ -0,0 +1,82 @@
; test source file for assembling to COFF
; build with (under DJGPP, for example):
; yasm -f coff cofftest.asm
; gcc -o cofftest cofftest.c cofftest.o
; 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] ; [1]
[GLOBAL _greet] ; [1]
[GLOBAL _asmstr] ; [2]
[GLOBAL _textptr] ; [2]
[GLOBAL _selfptr] ; [2]
[GLOBAL _integer] ; [3]
[EXTERN _printf] ; [10]
[COMMON _commvar 4] ; [7]
[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 mov eax,[_integer] ; [14]
inc eax
mov [localint],eax ; [14]
push dword [_commvar]
mov eax,[localptr] ; [13]
push dword [eax]
push dword [_integer] ; [1] [14]
push dword _printfstr ; [13]
call _printf ; [11]
add esp,16
ret
[SECTION .data]
; a string
_asmstr db 'hello, world', 0 ; [2]
; 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 ; [15]
_selfptr dd _selfptr ; [16]
[SECTION .bss]
; an integer
_integer resd 1 ; [3]
; a local integer
localint resd 1 ; [6]

@ -0,0 +1,34 @@
/*
* test source file for assembling to COFF
* build with (under DJGPP, for example):
* yasm -f coff cofftest.asm
* gcc -o cofftest cofftest.c cofftest.o
*/
#include <stdio.h>
extern int lrotate(long, int);
extern void greet(void);
extern char asmstr[];
extern void *selfptr;
extern void *textptr;
extern int integer, commvar;
int main(void) {
printf("Testing lrotate: should get 0x00400000, 0x00000001\n");
printf("lrotate(0x00040000, 4) = 0x%08lx\n", lrotate(0x40000,4));
printf("lrotate(0x00040000, 14) = 0x%08lx\n", lrotate(0x40000,14));
printf("This string should read `hello, world': `%s'\n", asmstr);
printf("The integers here should be 1234, 1235 and 4321:\n");
integer = 1234;
commvar = 4321;
greet();
printf("These pointers should be equal: %p and %p\n",
&greet, textptr);
printf("So should these: %p and %p\n", selfptr, &selfptr);
}

@ -0,0 +1,660 @@
4c
01
03
00
00
00
00
00
70
01
00
00
10
00
00
00
00
00
0c
01
2e
74
65
78
74
00
00
00
00
00
00
00
00
00
00
00
40
00
00
00
8c
00
00
00
cc
00
00
00
00
00
00
00
07
00
00
00
20
00
50
60
2e
64
61
74
61
00
00
00
40
00
00
00
00
00
00
00
40
00
00
00
12
01
00
00
52
01
00
00
00
00
00
00
03
00
00
00
40
00
30
c0
2e
62
73
73
00
00
00
00
80
00
00
00
00
00
00
00
08
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
80
00
30
c0
55
89
e5
8b
45
08
8b
4d
0c
d1
c0
e2
fc
89
ec
5d
c3
a1
00
00
00
00
40
a3
04
00
00
00
ff
35
00
00
00
00
a1
34
00
00
00
ff
30
ff
35
00
00
00
00
68
0d
00
00
00
e8
00
00
00
00
81
c4
10
00
00
00
c3
12
00
00
00
0e
00
00
00
06
00
18
00
00
00
0e
00
00
00
06
00
1e
00
00
00
0b
00
00
00
06
00
23
00
00
00
0c
00
00
00
06
00
2b
00
00
00
0e
00
00
00
06
00
30
00
00
00
0c
00
00
00
06
00
35
00
00
00
0a
00
00
00
14
00
68
65
6c
6c
6f
2c
20
77
6f
72
6c
64
00
69
6e
74
65
67
65
72
3d
3d
25
64
2c
20
6c
6f
63
61
6c
69
6e
74
3d
3d
25
64
2c
20
63
6f
6d
6d
76
61
72
3d
25
64
0a
00
04
00
00
00
11
00
00
00
3c
00
00
00
34
00
00
00
0e
00
00
00
06
00
38
00
00
00
02
00
00
00
06
00
3c
00
00
00
0c
00
00
00
06
00
2e
66
69
6c
65
00
00
00
00
00
00
00
fe
ff
00
00
67
01
2d
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
2e
74
65
78
74
00
00
00
00
00
00
00
01
00
00
00
03
01
40
00
00
00
07
00
00
00
00
00
00
00
00
00
00
00
00
00
5f
6c
72
6f
74
61
74
65
00
00
00
00
01
00
00
00
02
00
5f
67
72
65
65
74
00
00
11
00
00
00
01
00
00
00
02
00
5f
61
73
6d
73
74
72
00
00
00
00
00
02
00
00
00
02
00
5f
74
65
78
74
70
74
72
38
00
00
00
02
00
00
00
02
00
5f
73
65
6c
66
70
74
72
3c
00
00
00
02
00
00
00
02
00
5f
69
6e
74
65
67
65
72
00
00
00
00
03
00
00
00
02
00
5f
70
72
69
6e
74
66
00
00
00
00
00
00
00
00
00
02
00
5f
63
6f
6d
6d
76
61
72
04
00
00
00
00
00
00
00
02
00
2e
64
61
74
61
00
00
00
00
00
00
00
02
00
00
00
03
01
40
00
00
00
03
00
00
00
00
00
00
00
00
00
00
00
00
00
2e
62
73
73
00
00
00
00
00
00
00
00
03
00
00
00
03
01
08
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
04
00
00
00
Loading…
Cancel
Save