BR 1828103: Fix %arg and %local
authorH. Peter Anvin <hpa@zytor.com>
Fri, 9 Nov 2007 04:01:11 +0000 (20:01 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 9 Nov 2007 04:01:11 +0000 (20:01 -0800)
Correct the implementation of %arg and %local.

It's questionable how much they make sense for 64-bit mode; even in
32-bit mode one normally make references off the stack pointer instead
of the base pointer (frame pointer), but that requires keeping track
of the stack pointer offset.

preproc.c
test/local.asm [new file with mode: 0644]

index 9bc6f71..ddfa3da 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -300,10 +300,6 @@ static int is_condition(enum preproc_token arg)
  * then jam in the equivalent NASM directive into the input stream.
  */
 
-#ifndef MAX
-#       define MAX(a,b) ( ((a) > (b)) ? (a) : (b))
-#endif
-
 enum {
     TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI,
     TM_IFNDEF, TM_INCLUDE, TM_LOCAL
@@ -317,7 +313,7 @@ static const char * const tasm_directives[] = {
 static int StackSize = 4;
 static char *StackPointer = "ebp";
 static int ArgOffset = 8;
-static int LocalOffset = 4;
+static int LocalOffset = 0;
 
 static Context *cstk;
 static Include *istk;
@@ -1718,6 +1714,18 @@ static void undef_smacro(Context *ctx, const char *mname)
     }
 }
 
+/*
+ * Decode a size directive
+ */
+static int parse_size(const char *str) {
+    static const char *size_names[] =
+       { "byte", "dword", "oword", "qword", "tword", "word" };
+    static const int sizes[] =
+       { 0, 1, 4, 16, 8, 10, 2 };
+
+    return sizes[bsii(str, size_names, elements(size_names))+1];
+}
+
 /**
  * find and process preprocessor directive in passed line
  * Find out if a line contains a preprocessor directive, and deal
@@ -1813,7 +1821,7 @@ static int do_directive(Token * tline)
             StackSize = 4;
             StackPointer = "ebp";
             ArgOffset = 8;
-            LocalOffset = 4;
+            LocalOffset = 0;
         } else if (nasm_stricmp(tline->text, "large") == 0) {
             /* All subsequent ARG directives are for a 16-bit stack,
              * far function call.
@@ -1821,7 +1829,7 @@ static int do_directive(Token * tline)
             StackSize = 2;
             StackPointer = "bp";
             ArgOffset = 4;
-            LocalOffset = 2;
+            LocalOffset = 0;
         } else if (nasm_stricmp(tline->text, "small") == 0) {
             /* All subsequent ARG directives are for a 16-bit stack,
              * far function call. We don't support near functions.
@@ -1829,7 +1837,7 @@ static int do_directive(Token * tline)
             StackSize = 2;
             StackPointer = "bp";
             ArgOffset = 6;
-            LocalOffset = 2;
+            LocalOffset = 0;
         } else {
             error(ERR_NONFATAL, "`%%stacksize' invalid size type");
             free_tlist(origline);
@@ -1879,17 +1887,8 @@ static int do_directive(Token * tline)
             /* Allow macro expansion of type parameter */
             tt = tokenize(tline->text);
             tt = expand_smacro(tt);
-            if (nasm_stricmp(tt->text, "byte") == 0) {
-                size = MAX(StackSize, 1);
-            } else if (nasm_stricmp(tt->text, "word") == 0) {
-                size = MAX(StackSize, 2);
-            } else if (nasm_stricmp(tt->text, "dword") == 0) {
-                size = MAX(StackSize, 4);
-            } else if (nasm_stricmp(tt->text, "qword") == 0) {
-                size = MAX(StackSize, 8);
-            } else if (nasm_stricmp(tt->text, "tword") == 0) {
-                size = MAX(StackSize, 10);
-            } else {
+           size = parse_size(tt->text);
+           if (!size) {
                 error(ERR_NONFATAL,
                       "Invalid size type for `%%arg' missing directive");
                 free_tlist(tt);
@@ -1898,6 +1897,9 @@ static int do_directive(Token * tline)
             }
             free_tlist(tt);
 
+           /* Round up to even stack slots */
+           size = (size+StackSize-1) & ~(StackSize-1);
+
             /* Now define the macro for the argument */
             snprintf(directive, sizeof(directive), "%%define %s (%s+%d)",
                      arg, StackPointer, offset);
@@ -1908,8 +1910,8 @@ static int do_directive(Token * tline)
             tline = tline->next;
             if (tline && tline->type == TOK_WHITESPACE)
                 tline = tline->next;
-        }
-        while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
+        } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
+       ArgOffset = offset;
         free_tlist(origline);
         return DIRECTIVE_FOUND;
 
@@ -1960,17 +1962,8 @@ static int do_directive(Token * tline)
             /* Allow macro expansion of type parameter */
             tt = tokenize(tline->text);
             tt = expand_smacro(tt);
-            if (nasm_stricmp(tt->text, "byte") == 0) {
-                size = MAX(StackSize, 1);
-            } else if (nasm_stricmp(tt->text, "word") == 0) {
-                size = MAX(StackSize, 2);
-            } else if (nasm_stricmp(tt->text, "dword") == 0) {
-                size = MAX(StackSize, 4);
-            } else if (nasm_stricmp(tt->text, "qword") == 0) {
-                size = MAX(StackSize, 8);
-            } else if (nasm_stricmp(tt->text, "tword") == 0) {
-                size = MAX(StackSize, 10);
-            } else {
+           size = parse_size(tt->text);
+           if (!size) {
                 error(ERR_NONFATAL,
                       "Invalid size type for `%%local' missing directive");
                 free_tlist(tt);
@@ -1979,11 +1972,15 @@ static int do_directive(Token * tline)
             }
             free_tlist(tt);
 
-            /* Now define the macro for the argument */
+           /* Round up to even stack slots */
+           size = (size+StackSize-1) & ~(StackSize-1);
+
+            offset += size;    /* Negative offset, increment before */
+
+           /* Now define the macro for the argument */
             snprintf(directive, sizeof(directive), "%%define %s (%s-%d)",
                      local, StackPointer, offset);
             do_directive(tokenize(directive));
-            offset += size;
 
             /* Now define the assign to setup the enter_c macro correctly */
             snprintf(directive, sizeof(directive),
@@ -1994,8 +1991,8 @@ static int do_directive(Token * tline)
             tline = tline->next;
             if (tline && tline->type == TOK_WHITESPACE)
                 tline = tline->next;
-        }
-        while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
+        } while (tline && tline->type == TOK_OTHER && tline->text[0] == ',');
+       LocalOffset = offset;
         free_tlist(origline);
         return DIRECTIVE_FOUND;
 
diff --git a/test/local.asm b/test/local.asm
new file mode 100644 (file)
index 0000000..64a0e59
--- /dev/null
@@ -0,0 +1,18 @@
+       bits 32
+
+%push bluttan
+
+%define %$localsize 0
+
+%stacksize flat
+%local l1:qword, l2:dword, l3:dword, l4:qword
+%arg a1:qword, a2:dword, a3:dword, a4:qword
+
+       mov eax,[a1]
+       mov ebx,[a2]
+       mov ecx,[a3]
+       mov edx,[a4]
+       mov [l1],eax
+       mov [l2],ebx
+       mov [l3],ecx
+       mov [l4],edx