Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 6428 → Rev 6429

/programs/develop/ktcc/trunk/source/tccasm.c
18,7 → 18,10
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
static int asm_get_local_label_name(TCCState *s1, unsigned int n)
#include "tcc.h"
#ifdef CONFIG_TCC_ASM
 
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
{
char buf[64];
TokenSym *ts;
28,7 → 31,9
return ts->tok;
}
 
static void asm_expr(TCCState *s1, ExprValue *pe);
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
static int tcc_assemble_internal(TCCState *s1, int do_preprocess);
static Sym sym_dot;
 
/* We do not use the C expression parser to handle symbols. Maybe the
C expression parser could be tweaked to do so. */
41,7 → 46,7
 
switch(tok) {
case TOK_PPNUM:
p = tokc.cstr->data;
p = tokc.str.data;
n = strtoul(p, (char **)&p, 0);
if (*p == 'b' || *p == 'f') {
/* backward or forward label */
52,7 → 57,7
if (sym && sym->r == 0)
sym = sym->prev_tok;
if (!sym)
error("local label '%d' not found backward", n);
tcc_error("local label '%d' not found backward", n);
} else {
/* forward */
if (!sym || sym->r) {
67,7 → 72,7
pe->v = n;
pe->sym = NULL;
} else {
error("invalid number syntax");
tcc_error("invalid number syntax");
}
next();
break;
81,7 → 86,7
next();
asm_expr_unary(s1, pe);
if (pe->sym)
error("invalid operation with label");
tcc_error("invalid operation with label");
if (op == '-')
pe->v = -pe->v;
else
98,6 → 103,14
asm_expr(s1, pe);
skip(')');
break;
case '.':
pe->v = 0;
pe->sym = &sym_dot;
sym_dot.type.t = VT_VOID | VT_STATIC;
sym_dot.r = cur_text_section->sh_num;
sym_dot.jnext = ind;
next();
break;
default:
if (tok >= TOK_IDENT) {
/* label case : if the label was not found, add one */
109,7 → 122,7
}
if (sym->r == SHN_ABS) {
/* if absolute symbol, no need to put a symbol value */
pe->v = (long)sym->next;
pe->v = sym->jnext;
pe->sym = NULL;
} else {
pe->v = 0;
117,7 → 130,7
}
next();
} else {
error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
}
break;
}
137,7 → 150,7
next();
asm_expr_unary(s1, &e2);
if (pe->sym || e2.sym)
error("invalid operation with label");
tcc_error("invalid operation with label");
switch(op) {
case '*':
pe->v *= e2.v;
145,7 → 158,7
case '/':
if (e2.v == 0) {
div_error:
error("division by zero");
tcc_error("division by zero");
}
pe->v /= e2.v;
break;
178,7 → 191,7
next();
asm_expr_prod(s1, &e2);
if (pe->sym || e2.sym)
error("invalid operation with label");
tcc_error("invalid operation with label");
switch(op) {
case '&':
pe->v &= e2.v;
225,25 → 238,25
/* OK */
} else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
/* we also accept defined symbols in the same section */
pe->v += (long)pe->sym->next - (long)e2.sym->next;
pe->v += pe->sym->jnext - e2.sym->jnext;
} else {
goto cannot_relocate;
}
pe->sym = NULL; /* same symbols can be substracted to NULL */
pe->sym = NULL; /* same symbols can be subtracted to NULL */
} else {
cannot_relocate:
error("invalid operation with label");
tcc_error("invalid operation with label");
}
}
}
}
 
static void asm_expr(TCCState *s1, ExprValue *pe)
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe)
{
asm_expr_sum(s1, pe);
}
 
static int asm_int_expr(TCCState *s1)
ST_FUNC int asm_int_expr(TCCState *s1)
{
ExprValue e;
asm_expr(s1, &e);
264,7 → 277,7
if (sym->r) {
/* the label is already defined */
if (!is_local) {
error("assembler label '%s' already defined",
tcc_error("assembler label '%s' already defined",
get_tok_str(label, NULL));
} else {
/* redefinition of local labels is possible */
277,7 → 290,7
sym->type.t = VT_STATIC | VT_VOID;
}
sym->r = sh_num;
sym->next = (void *)value;
sym->jnext = value;
}
 
static void asm_new_label(TCCState *s1, int label, int is_local)
298,7 → 311,7
sec = SECTION_ABS;
else
sec = st->sections[s->r];
put_extern_sym2(s, sec, (long)s->next, 0, 0);
put_extern_sym2(s, sec, s->jnext, 0, 0);
}
/* remove label */
table_ident[s->v - TOK_IDENT]->sym_label = NULL;
328,18 → 341,25
uint8_t *ptr;
 
/* assembler directive */
next();
sec = cur_text_section;
switch(tok) {
case TOK_ASM_align:
case TOK_ASM_skip:
case TOK_ASM_space:
case TOK_ASMDIR_align:
case TOK_ASMDIR_p2align:
case TOK_ASMDIR_skip:
case TOK_ASMDIR_space:
tok1 = tok;
next();
n = asm_int_expr(s1);
if (tok1 == TOK_ASM_align) {
if (tok1 == TOK_ASMDIR_p2align)
{
if (n < 0 || n > 30)
tcc_error("invalid p2align, must be between 0 and 30");
n = 1 << n;
tok1 = TOK_ASMDIR_align;
}
if (tok1 == TOK_ASMDIR_align) {
if (n < 0 || (n & (n-1)) != 0)
error("alignment must be a positive power of two");
tcc_error("alignment must be a positive power of two");
offset = (ind + n - 1) & -n;
size = offset - ind;
/* the section must have a compatible alignment */
361,16 → 381,16
}
ind += size;
break;
case TOK_ASM_quad:
case TOK_ASMDIR_quad:
next();
for(;;) {
uint64_t vl;
const char *p;
 
p = tokc.cstr->data;
p = tokc.str.data;
if (tok != TOK_PPNUM) {
error_constant:
error("64 bit constant");
tcc_error("64 bit constant");
}
vl = strtoll(p, (char **)&p, 0);
if (*p != '\0')
388,15 → 408,15
next();
}
break;
case TOK_ASM_byte:
case TOK_ASMDIR_byte:
size = 1;
goto asm_data;
case TOK_ASM_word:
case TOK_SHORT:
case TOK_ASMDIR_word:
case TOK_ASMDIR_short:
size = 2;
goto asm_data;
case TOK_LONG:
case TOK_INT:
case TOK_ASMDIR_long:
case TOK_ASMDIR_int:
size = 4;
asm_data:
next();
422,7 → 442,7
next();
}
break;
case TOK_ASM_fill:
case TOK_ASMDIR_fill:
{
int repeat, size, val, i, j;
uint8_t repeat_buf[8];
429,7 → 449,7
next();
repeat = asm_int_expr(s1);
if (repeat < 0) {
error("repeat < 0; .fill ignored");
tcc_error("repeat < 0; .fill ignored");
break;
}
size = 1;
438,7 → 458,7
next();
size = asm_int_expr(s1);
if (size < 0) {
error("size < 0; .fill ignored");
tcc_error("size < 0; .fill ignored");
break;
}
if (size > 8)
464,22 → 484,52
}
}
break;
case TOK_ASM_org:
case TOK_ASMDIR_rept:
{
int repeat;
TokenString init_str;
ParseState saved_parse_state = {0};
next();
repeat = asm_int_expr(s1);
tok_str_new(&init_str);
next();
while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
tok_str_add_tok(&init_str);
next();
}
if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
next();
tok_str_add(&init_str, -1);
tok_str_add(&init_str, 0);
save_parse_state(&saved_parse_state);
begin_macro(&init_str, 0);
while (repeat-- > 0) {
tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS));
macro_ptr = init_str.str;
}
end_macro();
restore_parse_state(&saved_parse_state);
break;
}
case TOK_ASMDIR_org:
{
unsigned long n;
next();
/* XXX: handle section symbols too */
n = asm_int_expr(s1);
if (n < ind)
error("attempt to .org backwards");
tcc_error("attempt to .org backwards");
v = 0;
size = n - ind;
goto zero_pad;
}
break;
case TOK_ASM_globl:
case TOK_ASM_global:
{
case TOK_ASMDIR_globl:
case TOK_ASMDIR_global:
case TOK_ASMDIR_weak:
case TOK_ASMDIR_hidden:
tok1 = tok;
do {
Sym *sym;
 
next();
488,13 → 538,18
sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID;
}
if (tok1 != TOK_ASMDIR_hidden)
sym->type.t &= ~VT_STATIC;
if (tok1 == TOK_ASMDIR_weak)
sym->type.t |= VT_WEAK;
else if (tok1 == TOK_ASMDIR_hidden)
sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
next();
}
} while (tok == ',');
break;
case TOK_ASM_string:
case TOK_ASM_ascii:
case TOK_ASM_asciz:
case TOK_ASMDIR_string:
case TOK_ASMDIR_ascii:
case TOK_ASMDIR_asciz:
{
const uint8_t *p;
int i, size, t;
504,9 → 559,9
for(;;) {
if (tok != TOK_STR)
expect("string constant");
p = tokc.cstr->data;
size = tokc.cstr->size;
if (t == TOK_ASM_ascii && size > 0)
p = tokc.str.data;
size = tokc.str.size;
if (t == TOK_ASMDIR_ascii && size > 0)
size--;
for(i = 0; i < size; i++)
g(p[i]);
519,9 → 574,9
}
}
break;
case TOK_ASM_text:
case TOK_ASM_data:
case TOK_ASM_bss:
case TOK_ASMDIR_text:
case TOK_ASMDIR_data:
case TOK_ASMDIR_bss:
{
char sname[64];
tok1 = tok;
531,12 → 586,104
n = asm_int_expr(s1);
next();
}
sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n);
if (n)
sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n);
else
sprintf(sname, "%s", get_tok_str(tok1, NULL));
use_section(s1, sname);
}
break;
case TOK_SECTION1:
case TOK_ASMDIR_file:
{
char filename[512];
 
filename[0] = '\0';
next();
 
if (tok == TOK_STR)
pstrcat(filename, sizeof(filename), tokc.str.data);
else
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
 
if (s1->warn_unsupported)
tcc_warning("ignoring .file %s", filename);
 
next();
}
break;
case TOK_ASMDIR_ident:
{
char ident[256];
 
ident[0] = '\0';
next();
 
if (tok == TOK_STR)
pstrcat(ident, sizeof(ident), tokc.str.data);
else
pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL));
 
if (s1->warn_unsupported)
tcc_warning("ignoring .ident %s", ident);
 
next();
}
break;
case TOK_ASMDIR_size:
{
Sym *sym;
 
next();
sym = label_find(tok);
if (!sym) {
tcc_error("label not found: %s", get_tok_str(tok, NULL));
}
 
/* XXX .size name,label2-label1 */
if (s1->warn_unsupported)
tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
 
next();
skip(',');
while (tok != '\n' && tok != CH_EOF) {
next();
}
}
break;
case TOK_ASMDIR_type:
{
Sym *sym;
const char *newtype;
 
next();
sym = label_find(tok);
if (!sym) {
sym = label_push(&s1->asm_labels, tok, 0);
sym->type.t = VT_VOID;
}
 
next();
skip(',');
if (tok == TOK_STR) {
newtype = tokc.str.data;
} else {
if (tok == '@' || tok == '%')
next();
newtype = get_tok_str(tok, NULL);
}
 
if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC;
}
else if (s1->warn_unsupported)
tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
get_tok_str(sym->v, NULL), sym->type.t, newtype);
 
next();
}
break;
case TOK_ASMDIR_section:
{
char sname[256];
 
/* XXX: support more options */
544,7 → 691,7
sname[0] = '\0';
while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
if (tok == TOK_STR)
pstrcat(sname, sizeof(sname), tokc.cstr->data);
pstrcat(sname, sizeof(sname), tokc.str.data);
else
pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
next();
555,24 → 702,50
if (tok != TOK_STR)
expect("string constant");
next();
if (tok == ',') {
next();
if (tok == '@' || tok == '%')
next();
next();
}
}
last_text_section = cur_text_section;
use_section(s1, sname);
}
break;
case TOK_ASM_previous:
case TOK_ASMDIR_previous:
{
Section *sec;
next();
if (!last_text_section)
error("no previous section referenced");
tcc_error("no previous section referenced");
sec = cur_text_section;
use_section1(s1, last_text_section);
last_text_section = sec;
}
break;
#ifdef TCC_TARGET_I386
case TOK_ASMDIR_code16:
{
next();
s1->seg_size = 16;
}
break;
case TOK_ASMDIR_code32:
{
next();
s1->seg_size = 32;
}
break;
#endif
#ifdef TCC_TARGET_X86_64
/* added for compatibility with GAS */
case TOK_ASMDIR_code64:
next();
break;
#endif
default:
error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
break;
}
}
619,7 → 792,7
 
ch = file->buf_ptr[0];
tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
parse_flags = PARSE_FLAG_ASM_COMMENTS;
parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
if (do_preprocess)
parse_flags |= PARSE_FLAG_PREPROCESS;
next();
632,12 → 805,12
/* horrible gas comment */
while (tok != TOK_LINEFEED)
next();
} else if (tok == '.') {
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
asm_parse_directive(s1);
} else if (tok == TOK_PPNUM) {
const char *p;
int n;
p = tokc.cstr->data;
p = tokc.str.data;
n = strtoul(p, (char **)&p, 10);
if (*p != '\0')
expect("':'");
679,7 → 852,7
}
 
/* Assemble the current file */
static int tcc_assemble(TCCState *s1, int do_preprocess)
ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
{
Sym *define_start;
int ret;
692,6 → 865,12
 
define_start = define_stack;
 
/* an elf symbol of type STT_FILE must be put so that STB_LOCAL
symbols can be safely used */
put_elf_sym(symtab_section, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
SHN_ABS, file->filename);
 
ret = tcc_assemble_internal(s1, do_preprocess);
 
cur_text_section->data_offset = ind;
709,37 → 888,27
end */
static void tcc_assemble_inline(TCCState *s1, char *str, int len)
{
BufferedFile *bf, *saved_file;
int saved_parse_flags, *saved_macro_ptr;
int saved_parse_flags;
const int *saved_macro_ptr;
 
bf = tcc_malloc(sizeof(BufferedFile));
memset(bf, 0, sizeof(BufferedFile));
bf->fd = -1;
bf->buf_ptr = str;
bf->buf_end = str + len;
str[len] = CH_EOB;
/* same name as current file so that errors are correctly
reported */
pstrcpy(bf->filename, sizeof(bf->filename), file->filename);
bf->line_num = file->line_num;
saved_file = file;
file = bf;
saved_parse_flags = parse_flags;
saved_macro_ptr = macro_ptr;
 
tcc_open_bf(s1, ":asm:", len);
memcpy(file->buffer, str, len);
 
macro_ptr = NULL;
tcc_assemble_internal(s1, 0);
tcc_close();
 
parse_flags = saved_parse_flags;
macro_ptr = saved_macro_ptr;
file = saved_file;
tcc_free(bf);
}
 
/* find a constraint by its number or id (gcc 3 extended
syntax). return -1 if not found. Return in *pp in char after the
constraint */
static int find_constraint(ASMOperand *operands, int nb_operands,
ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands,
const char *name, const char **pp)
{
int index;
801,12 → 970,12
modifier = *str++;
index = find_constraint(operands, nb_operands, str, &str);
if (index < 0)
error("invalid operand reference after %%");
tcc_error("invalid operand reference after %%");
op = &operands[index];
sv = *op->vt;
if (op->reg >= 0) {
sv.r = op->reg;
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL)
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
sv.r |= VT_LVAL;
}
subst_asm_operand(out_str, &sv, modifier);
830,7 → 999,7
nb_operands = *nb_operands_ptr;
for(;;) {
if (nb_operands >= MAX_ASM_OPERANDS)
error("too many asm operands");
tcc_error("too many asm operands");
op = &operands[nb_operands++];
op->id = 0;
if (tok == '[') {
843,8 → 1012,8
}
if (tok != TOK_STR)
expect("string constant");
op->constraint = tcc_malloc(tokc.cstr->size);
strcpy(op->constraint, tokc.cstr->data);
op->constraint = tcc_malloc(tokc.str.size);
strcpy(op->constraint, tokc.str.data);
next();
skip('(');
gexpr();
874,27 → 1043,12
}
}
 
static void parse_asm_str(CString *astr)
{
skip('(');
/* read the string */
if (tok != TOK_STR)
expect("string constant");
cstr_new(astr);
while (tok == TOK_STR) {
/* XXX: add \0 handling too ? */
cstr_cat(astr, tokc.cstr->data);
next();
}
cstr_ccat(astr, '\0');
}
 
/* parse the GCC asm() instruction */
static void asm_instr(void)
ST_FUNC void asm_instr(void)
{
CString astr, astr1;
ASMOperand operands[MAX_ASM_OPERANDS];
int nb_inputs, nb_outputs, nb_operands, i, must_subst, out_reg;
int nb_outputs, nb_operands, i, must_subst, out_reg;
uint8_t clobber_regs[NB_ASM_REGS];
 
next();
916,6 → 1070,7
nb_outputs = nb_operands;
if (tok == ':') {
next();
if (tok != ')') {
/* input args */
parse_asm_operands(operands, &nb_operands, 0);
if (tok == ':') {
925,7 → 1080,7
for(;;) {
if (tok != TOK_STR)
expect("string constant");
asm_clobber(clobber_regs, tokc.cstr->data);
asm_clobber(clobber_regs, tokc.str.data);
next();
if (tok == ',') {
next();
936,12 → 1091,12
}
}
}
}
skip(')');
/* NOTE: we do not eat the ';' so that we can restore the current
token after the assembler parsing */
if (tok != ';')
expect("';'");
nb_inputs = nb_operands - nb_outputs;
/* save all values in the memory */
save_regs(0);
989,7 → 1144,7
cstr_free(&astr1);
}
 
static void asm_global_instr(void)
ST_FUNC void asm_global_instr(void)
{
CString astr;
 
1017,3 → 1172,4
 
cstr_free(&astr);
}
#endif /* CONFIG_TCC_ASM */