mirror of https://git.wuffs.org/MWCC
681 lines
20 KiB
C
681 lines
20 KiB
C
#include "compiler/InlineAsm.h"
|
|
#include "compiler/InlineAsmPPC.h"
|
|
#include "compiler/GCCInlineAsm.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInit.h"
|
|
#include "compiler/CInline.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/COptimizer.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CPrep.h"
|
|
#include "compiler/CPrepTokenizer.h"
|
|
#include "compiler/CScope.h"
|
|
#include "compiler/PCode.h"
|
|
#include "compiler/Registers.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/scopes.h"
|
|
#include "compiler/types.h"
|
|
|
|
int allow_array_expressions = 1;
|
|
|
|
int backtracking;
|
|
jmp_buf backtrack;
|
|
jmp_buf InlineAsm_assemblererror;
|
|
static int ASMstmtnb;
|
|
|
|
void AssemblerError(void) {
|
|
longjmp(InlineAsm_assemblererror, 1);
|
|
}
|
|
|
|
void InlineAsm_SyntaxError(short code) {
|
|
if (backtracking)
|
|
longjmp(backtrack, 1);
|
|
|
|
if (tk == TK_EOL || tk == ';')
|
|
code = CErrorStr112;
|
|
CError_Error(code);
|
|
}
|
|
|
|
CLabel *InlineAsm_LookupLabel(HashNameNode *name) {
|
|
CLabel *label;
|
|
|
|
for (label = Labels; label; label = label->next) {
|
|
if (name == label->name)
|
|
break;
|
|
}
|
|
|
|
return label;
|
|
}
|
|
|
|
CLabel *InlineAsm_DeclareLabel(HashNameNode *name) {
|
|
CLabel *label = newlabel();
|
|
label->name = name;
|
|
label->next = Labels;
|
|
Labels = label;
|
|
return label;
|
|
}
|
|
|
|
static void InlineAsm_DefineLabel(HashNameNode *name) {
|
|
CLabel *label;
|
|
Statement *stmt;
|
|
|
|
label = InlineAsm_LookupLabel(name);
|
|
if (!label) {
|
|
label = InlineAsm_DeclareLabel(name);
|
|
} else {
|
|
if (label->stmt)
|
|
CError_Error(CErrorStr171, name->name);
|
|
}
|
|
|
|
stmt = CFunc_AppendStatement(ST_LABEL);
|
|
stmt->label = label;
|
|
label->stmt = stmt;
|
|
}
|
|
|
|
Boolean InlineAsm_LookupSymbolOrTag(HashNameNode *name, IALookupResult *result, Boolean allow_tag) {
|
|
ObjBase *obj;
|
|
NameSpace *nspace;
|
|
NameSpaceObjectList *list;
|
|
|
|
result->name = name;
|
|
result->object = NULL;
|
|
result->label = NULL;
|
|
result->type = NULL;
|
|
result->has_value = 0;
|
|
|
|
if ((result->label = InlineAsm_LookupLabel(name)))
|
|
return 1;
|
|
|
|
for (nspace = cscope_current; nspace; nspace = nspace->parent) {
|
|
if ((list = CScope_FindName(nspace, name))) {
|
|
obj = list->object;
|
|
switch (obj->otype) {
|
|
case OT_ENUMCONST:
|
|
result->has_value = 1;
|
|
result->value = OBJ_ENUM_CONST(list->object)->val.lo;
|
|
return 1;
|
|
case OT_OBJECT:
|
|
if (OBJECT(obj)->datatype == DABSOLUTE) {
|
|
result->has_value = 1;
|
|
result->value = OBJECT(obj)->u.address;
|
|
} else {
|
|
if (OBJECT(obj)->datatype == DDATA && (OBJECT(obj)->qual & Q_10000))
|
|
CInit_ExportConst(OBJECT(obj));
|
|
result->object = OBJECT(obj);
|
|
}
|
|
return 1;
|
|
case OT_TYPE:
|
|
result->type = OBJ_TYPE(obj)->type;
|
|
return 1;
|
|
case OT_TYPETAG:
|
|
if (allow_tag) {
|
|
result->type = OBJ_TYPE_TAG(obj)->type;
|
|
return 1;
|
|
}
|
|
case OT_NAMESPACE:
|
|
case OT_MEMBERVAR:
|
|
return 0;
|
|
default:
|
|
CError_FATAL(245);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
Boolean InlineAsm_LookupSymbol(HashNameNode *name, IALookupResult *result) {
|
|
return InlineAsm_LookupSymbolOrTag(name, result, 0);
|
|
}
|
|
|
|
static ObjMemberVar *isclassmember(TypeClass *tclass, HashNameNode *name) {
|
|
NameSpaceObjectList *list;
|
|
|
|
list = CScope_FindName(tclass->nspace, name);
|
|
return (list && list->object->otype == OT_MEMBERVAR) ? OBJ_MEMBER_VAR(list->object) : NULL;
|
|
}
|
|
|
|
SInt32 InlineAsm_StructMemberOffset(Type *type) {
|
|
StructMember *member;
|
|
ObjMemberVar *ivar;
|
|
SInt32 offset = 0;
|
|
|
|
do {
|
|
if (IS_TYPE_STRUCT(type)) {
|
|
tk = lex();
|
|
if (tk != TK_IDENTIFIER)
|
|
InlineAsm_SyntaxError(CErrorStr107);
|
|
member = ismember(TYPE_STRUCT(type), tkidentifier);
|
|
if (!member)
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
offset += member->offset;
|
|
type = member->type;
|
|
tk = lex();
|
|
} else if (IS_TYPE_CLASS(type)) {
|
|
tk = lex();
|
|
if (tk != TK_IDENTIFIER)
|
|
InlineAsm_SyntaxError(CErrorStr107);
|
|
ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
|
|
if (!ivar)
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
offset += ivar->offset;
|
|
type = ivar->type;
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr149);
|
|
}
|
|
} while (tk == '.');
|
|
|
|
return offset;
|
|
}
|
|
|
|
SInt32 InlineAsm_StructArrayMemberOffset(Type *type) {
|
|
StructMember *member;
|
|
ObjMemberVar *ivar;
|
|
SInt32 offset = 0;
|
|
|
|
do {
|
|
if (tk == '.') {
|
|
if (IS_TYPE_STRUCT(type)) {
|
|
tk = lex();
|
|
if (tk != TK_IDENTIFIER)
|
|
InlineAsm_SyntaxError(CErrorStr107);
|
|
member = ismember(TYPE_STRUCT(type), tkidentifier);
|
|
if (!member)
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
offset += member->offset;
|
|
type = member->type;
|
|
tk = lex();
|
|
} else if (IS_TYPE_CLASS(type)) {
|
|
tk = lex();
|
|
if (tk != TK_IDENTIFIER)
|
|
InlineAsm_SyntaxError(CErrorStr107);
|
|
ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
|
|
if (!ivar)
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
offset += ivar->offset;
|
|
type = ivar->type;
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr149);
|
|
}
|
|
} else {
|
|
if (IS_TYPE_ARRAY(type)) {
|
|
type = TPTR_TARGET(type);
|
|
tk = lex();
|
|
offset += type->size * InlineAsm_ConstantExpression();
|
|
if (tk != ']')
|
|
InlineAsm_SyntaxError(125);
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr148);
|
|
}
|
|
}
|
|
} while (tk == '.' || tk == '[');
|
|
|
|
return offset;
|
|
}
|
|
|
|
SInt32 InlineAsm_StructPointerMemberOffset(Type *type) {
|
|
StructMember *member;
|
|
ObjMemberVar *ivar;
|
|
SInt32 offset;
|
|
|
|
tk = lex();
|
|
if (tk != TK_IDENTIFIER)
|
|
InlineAsm_SyntaxError(107);
|
|
|
|
if (IS_TYPE_STRUCT(type)) {
|
|
member = ismember(TYPE_STRUCT(type), tkidentifier);
|
|
if (!member)
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
offset = member->offset;
|
|
type = member->type;
|
|
} else {
|
|
ivar = isclassmember(TYPE_CLASS(type), tkidentifier);
|
|
if (!ivar)
|
|
CError_Error(CErrorStr150, tkidentifier->name);
|
|
offset = ivar->offset;
|
|
type = ivar->type;
|
|
}
|
|
|
|
tk = lex();
|
|
if (tk == '.' || tk == '[')
|
|
offset += InlineAsm_StructArrayMemberOffset(type);
|
|
|
|
return offset;
|
|
}
|
|
|
|
static SInt32 DiadicOperator(SInt32 left, short op, SInt32 right) {
|
|
CInt64 left64;
|
|
CInt64 right64;
|
|
CInt64_SetLong(&left64, left);
|
|
CInt64_SetLong(&right64, right);
|
|
right64 = CMach_CalcIntDiadic(TYPE(&stsignedint), left64, op, right64);
|
|
return CInt64_GetULong(&right64);
|
|
}
|
|
|
|
static SInt32 PrimaryExpression(void) {
|
|
IALookupResult result;
|
|
SInt32 value;
|
|
|
|
switch (tk) {
|
|
case TK_IDENTIFIER:
|
|
if (InlineAsm_LookupSymbol(tkidentifier, &result)) {
|
|
if (result.has_value) {
|
|
tk = lex();
|
|
return result.value;
|
|
}
|
|
|
|
if (result.type && (IS_TYPE_STRUCT(result.type) || IS_TYPE_CLASS(result.type))) {
|
|
tk = lex();
|
|
if (tk != '.')
|
|
InlineAsm_SyntaxError(120);
|
|
if (allow_array_expressions)
|
|
return InlineAsm_StructArrayMemberOffset(result.type);
|
|
else
|
|
return InlineAsm_StructMemberOffset(result.type);
|
|
} else {
|
|
InlineAsm_SyntaxError(124);
|
|
}
|
|
} else {
|
|
InlineAsm_SyntaxError(124);
|
|
}
|
|
break;
|
|
case TK_INTCONST:
|
|
value = tkintconst.lo;
|
|
tk = lex();
|
|
return value;
|
|
case TK_SIZEOF:
|
|
return scansizeof();
|
|
case '+':
|
|
tk = lex();
|
|
return PrimaryExpression();
|
|
case '-':
|
|
tk = lex();
|
|
return -PrimaryExpression();
|
|
case '!':
|
|
tk = lex();
|
|
return PrimaryExpression() == 0;
|
|
case '~':
|
|
tk = lex();
|
|
return ~PrimaryExpression();
|
|
case '(':
|
|
tk = lex();
|
|
value = InlineAsm_ConstantExpression();
|
|
if (tk != ')')
|
|
InlineAsm_SyntaxError(115);
|
|
tk = lex();
|
|
return value;
|
|
default:
|
|
InlineAsm_SyntaxError(120);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static SInt32 ConstantExpressionTail(SInt32 value) {
|
|
SInt32 right;
|
|
short left_token;
|
|
short right_prec;
|
|
|
|
while (1) {
|
|
left_token = tk;
|
|
tk = lex();
|
|
right = PrimaryExpression();
|
|
|
|
right_prec = GetPrec(tk);
|
|
if (right_prec == 0)
|
|
return DiadicOperator(value, left_token, right);
|
|
|
|
if (GetPrec(left_token) >= right_prec) {
|
|
value = DiadicOperator(value, left_token, right);
|
|
} else {
|
|
value = DiadicOperator(value, left_token, ConstantExpressionTail(right));
|
|
if (GetPrec(tk) == 0)
|
|
return value;
|
|
}
|
|
}
|
|
}
|
|
|
|
SInt32 InlineAsm_ConstantExpression(void) {
|
|
SInt32 value = PrimaryExpression();
|
|
|
|
if (GetPrec(tk) == 0)
|
|
return value;
|
|
else
|
|
return ConstantExpressionTail(value);
|
|
}
|
|
|
|
HashNameNode *MakeLocalLabel(CInt64 num) {
|
|
char buf[80];
|
|
sprintf(buf, "@%i_%i", ASMstmtnb, CInt64_GetULong(&num));
|
|
return GetHashNameNodeExport(buf);
|
|
}
|
|
|
|
static void ScanOptionalLabel(void) {
|
|
if (tk == TK_INTCONST) {
|
|
if (lookahead() == ':') {
|
|
InlineAsm_DefineLabel(MakeLocalLabel(tkintconst));
|
|
tk = lex();
|
|
tk = lex();
|
|
}
|
|
} else {
|
|
if (tkidentifier->name[0] == '@') {
|
|
InlineAsm_DefineLabel(tkidentifier);
|
|
tk = lex();
|
|
if (tk == ':')
|
|
tk = lex();
|
|
} else {
|
|
HashNameNode *name = tkidentifier;
|
|
short t = lookahead();
|
|
tkidentifier = name;
|
|
if (t == ':') {
|
|
InlineAsm_DefineLabel(name);
|
|
tk = lex();
|
|
tk = lex();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ScanStatements(volatile short endToken, AssemblerType mode) {
|
|
if (setjmp(InlineAsm_assemblererror)) {
|
|
while (tk != TK_EOL && tk != endToken && tk != '}' && tk)
|
|
tk = lex();
|
|
if (tk == ';' || tk == TK_EOL)
|
|
tk = lex();
|
|
} else {
|
|
InlineAsm_Initialize(mode);
|
|
InlineAsm_gccmode = 0;
|
|
if (setjmp(InlineAsm_assemblererror)) {
|
|
while (tk != ';' && tk != TK_EOL && tk != endToken && tk != '}' && tk)
|
|
tk = lex();
|
|
if (tk == ';' || tk == TK_EOL)
|
|
tk = lex();
|
|
}
|
|
|
|
while (tk && tk != endToken) {
|
|
backtracking = 0;
|
|
sourceoffset = CPrep_GetFileOffsetInfo(&cparser_fileoffset);
|
|
if (tk == '"') {
|
|
if (InlineAsm_gccmode) {
|
|
tk = lex();
|
|
InlineAsm_gcc_parse();
|
|
} else {
|
|
InlineAsm_gccmode = 1;
|
|
copts.cplusplus = 0;
|
|
copts.asmpoundcomment = 1;
|
|
tk = lex();
|
|
}
|
|
}
|
|
|
|
if (tk == '.') {
|
|
InlineAsm_ScanAssemblyDirective();
|
|
} else if (tk == TK_IDENTIFIER) {
|
|
ScanOptionalLabel();
|
|
if (tk == TK_IDENTIFIER)
|
|
InlineAsm_ScanAssemblyInstruction();
|
|
} else if (tk == TK_INTCONST) {
|
|
ScanOptionalLabel();
|
|
if (tk == TK_IDENTIFIER)
|
|
InlineAsm_ScanAssemblyInstruction();
|
|
}
|
|
|
|
if (InlineAsm_gccmode && tk == '"') {
|
|
tk = lex();
|
|
InlineAsm_gcc_parse();
|
|
}
|
|
|
|
if (tk == ';' || tk == TK_EOL) {
|
|
CPrep_TokenStreamFlush();
|
|
tk = lex();
|
|
} else if (tk != endToken) {
|
|
if (endToken == ')')
|
|
CError_Error(CErrorStr115);
|
|
else
|
|
CError_Error(CErrorStr113);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void InlineAsm_ScanStatements(volatile short endToken) {
|
|
ScanStatements(endToken, AssemblerType_0);
|
|
}
|
|
|
|
void InlineAsm_ScanFunction(volatile short endToken) {
|
|
ScanStatements(endToken, AssemblerType_1);
|
|
}
|
|
|
|
void InlineAsm_Assemble(void) {
|
|
short token = (tk == '(') ? ')' : '}';
|
|
char save_pc = copts.asmpoundcomment;
|
|
char save_cpp = copts.cplusplus;
|
|
|
|
cprep_nostring = 1;
|
|
CFunc_AppendStatement(ST_NOP);
|
|
first_ST_ASM = curstmt;
|
|
ASMstmtnb++;
|
|
|
|
cprep_eoltokens = 1;
|
|
in_assembler = 1;
|
|
tk = lex();
|
|
InlineAsm_ScanStatements(token);
|
|
in_assembler = 0;
|
|
cprep_eoltokens = 0;
|
|
cprep_nostring = 0;
|
|
|
|
copts.asmpoundcomment = save_pc;
|
|
copts.cplusplus = save_cpp;
|
|
}
|
|
|
|
void InlineAsm_PackAsmStatement(Statement *stmt, Statement *first, void **output, SInt32 *outsize) {
|
|
InlineAsm *src;
|
|
InlineAsm *dest;
|
|
IAOperand *op;
|
|
SInt32 i;
|
|
SInt32 size;
|
|
|
|
src = (InlineAsm *) stmt->expr;
|
|
size = sizeof(InlineAsm) + sizeof(IAOperand) * src->argcount;
|
|
dest = galloc(size);
|
|
memcpy(dest, src, size);
|
|
|
|
for (i = 0, op = dest->args; i < dest->argcount; i++, op++) {
|
|
switch (op->type) {
|
|
case IAOpnd_0:
|
|
break;
|
|
case IAOpnd_Reg:
|
|
case IAOpnd_4:
|
|
op->u.reg.object = (Object *) CInline_GetLocalID(op->u.reg.object);
|
|
break;
|
|
case IAOpnd_Lab:
|
|
op->u.lab.label = (CLabel *) CInline_GetStatementNumber(first, op->u.lab.label->stmt);
|
|
break;
|
|
case IAOpnd_LabDiff:
|
|
op->u.labdiff.label1 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label1->stmt);
|
|
op->u.labdiff.label2 = (CLabel *) CInline_GetStatementNumber(first, op->u.labdiff.label2->stmt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
*output = dest;
|
|
*outsize = size;
|
|
}
|
|
|
|
void InlineAsm_UnpackAsmStatement(Statement *stmt, CLabel **labelArray, Boolean flag, void *data, SInt32 size) {
|
|
InlineAsm *ia;
|
|
IAOperand *op;
|
|
SInt32 i;
|
|
|
|
ia = galloc(size);
|
|
memcpy(ia, data, size);
|
|
|
|
for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
|
|
switch (op->type) {
|
|
case IAOpnd_0:
|
|
break;
|
|
case IAOpnd_Reg:
|
|
case IAOpnd_4:
|
|
op->u.reg.object = CInline_GetLocalObj((SInt32) op->u.reg.object, flag);
|
|
break;
|
|
case IAOpnd_Lab:
|
|
op->u.lab.label = labelArray[(SInt16) op->u.lab.label];
|
|
break;
|
|
case IAOpnd_LabDiff:
|
|
op->u.labdiff.label1 = labelArray[(SInt16) op->u.labdiff.label1];
|
|
op->u.labdiff.label2 = labelArray[(SInt16) op->u.labdiff.label2];
|
|
break;
|
|
}
|
|
}
|
|
|
|
stmt->expr = (ENode *) ia;
|
|
}
|
|
|
|
void InlineAsm_CheckLocalUsage(Statement *stmt) {
|
|
InlineAsm *ia = (InlineAsm *) stmt->expr;
|
|
IAOperand *op;
|
|
SInt32 i;
|
|
|
|
for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
|
|
switch (op->type) {
|
|
case IAOpnd_Reg:
|
|
if (op->u.reg.object)
|
|
SetVarUsage(op->u.reg.object, 0);
|
|
break;
|
|
case IAOpnd_4:
|
|
SetVarUsage(op->u.obj.obj, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CLabel *InlineAsm_GetReferencedLabel(Statement *stmt) {
|
|
InlineAsm *ia = (InlineAsm *) stmt->expr;
|
|
IAOperand *op;
|
|
SInt32 i;
|
|
|
|
for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
|
|
if (op->type == IAOpnd_Lab)
|
|
return op->u.lab.label;
|
|
if (op->type == IAOpnd_LabDiff)
|
|
return op->u.labdiff.label1;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CLabel *InlineAsm_GetReferencedLabel2(Statement *stmt) {
|
|
InlineAsm *ia = (InlineAsm *) stmt->expr;
|
|
IAOperand *op;
|
|
SInt32 i;
|
|
|
|
for (i = 0, op = ia->args; i < ia->argcount; i++, op++) {
|
|
if (op->type == IAOpnd_LabDiff)
|
|
return op->u.labdiff.label2;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Object *InlineAsm_GetObjectOffset(InlineAsm *ia, SInt32 index, SInt32 *offset) {
|
|
IAOperand *op;
|
|
SInt32 i;
|
|
SInt32 counter;
|
|
|
|
for (i = 0, counter = 0, op = ia->args; i < ia->argcount; i++, op++) {
|
|
if (op->type == IAOpnd_3) {
|
|
if (counter++ == index) {
|
|
*offset = ((intptr_t) &op->u.obj.obj) - ((intptr_t) ia);
|
|
return op->u.obj.obj;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
char *InlineAsm_DumpStatement(Statement *stmt) {
|
|
static char buffer[1024];
|
|
InlineAsm *ia;
|
|
IAOperand *arg;
|
|
int i;
|
|
char ch;
|
|
SInt32 offset;
|
|
|
|
ia = (InlineAsm *) stmt->expr;
|
|
|
|
strcpy(buffer, "\"");
|
|
strcat(buffer, InlineAsm_GetMnemonic(ia));
|
|
strcat(buffer, "\"");
|
|
|
|
for (i = 0, arg = ia->args; i < ia->argcount; i++, arg++) {
|
|
char argbuf[1024];
|
|
|
|
switch (arg->type) {
|
|
case IAOpnd_Imm:
|
|
sprintf(argbuf, " imm(%ld)", arg->u.imm.value);
|
|
break;
|
|
case IAOpnd_Reg:
|
|
ch = ' ';
|
|
if (arg->u.reg.effect & EffectWrite) {
|
|
if (arg->u.reg.effect & EffectRead)
|
|
ch = '+';
|
|
else
|
|
ch = '=';
|
|
} else {
|
|
if (!(arg->u.reg.effect & EffectRead))
|
|
ch = '0';
|
|
}
|
|
|
|
if (arg->u.reg.object) {
|
|
sprintf(argbuf,
|
|
"%creg(%s)",
|
|
ch,
|
|
arg->u.reg.object->name->name);
|
|
} else {
|
|
sprintf(argbuf,
|
|
"%creg(%s%d)",
|
|
ch,
|
|
register_class_name[arg->u.reg.rclass],
|
|
arg->u.reg.num);
|
|
}
|
|
break;
|
|
|
|
case IAOpnd_3:
|
|
case IAOpnd_4:
|
|
if (arg->u.obj.offset > 0)
|
|
sprintf(argbuf, " obj(%s+%ld)", arg->u.obj.obj->name->name, arg->u.obj.offset);
|
|
else if (arg->u.obj.offset < 0)
|
|
sprintf(argbuf, " obj(%s-%ld)", arg->u.obj.obj->name->name, -arg->u.obj.offset);
|
|
else
|
|
sprintf(argbuf, " obj(%s)", arg->u.obj.obj->name->name);
|
|
break;
|
|
|
|
case IAOpnd_Lab:
|
|
sprintf(argbuf, " lab(%s)", arg->u.lab.label->uniquename->name);
|
|
break;
|
|
|
|
case IAOpnd_LabDiff:
|
|
offset = !arg->negated ? 0 : arg->u.labdiff.offset;
|
|
sprintf(argbuf,
|
|
" labdiff(%s-%s%c%d)",
|
|
arg->u.labdiff.label1->uniquename->name,
|
|
arg->u.labdiff.label2->uniquename->name,
|
|
(arg->negated == 1) ? '-' : '+',
|
|
offset
|
|
);
|
|
break;
|
|
}
|
|
|
|
strcat(buffer, argbuf);
|
|
}
|
|
|
|
return buffer;
|
|
}
|