This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU as -- selevtively/dynamically disabling macro expansion


----- Forwarded message from Jagged <jagged@arcor.de> -----

I tried to address the maintainer mentioned in the as info pages as well
as the contributor of the listing capability, as given in the respective
source files.

For both these recipients I got an "undeliverable" message back, so now
I'm trying it here.

Date: Wed, 10 Oct 2012 20:05:13 +0200
From: Jagged <jagged@arcor.de>
To: raeburn@cygnus.com, sac@cygnus.com
Subject: GNU as -- selevtively/dynamically disabling macro expansion

High Ken, high Steve,

I'm using gas as a "stand alone" assembler, i. e. not as a backend for any
compiler. I'm doing low level stuff with no (as of now) interface to higher
level languages, and gas is my choice for doing the job of translating my
code to machine language.

Always repeating low level stuff can be boring, so I'm using a lot of macros,
which is not comfortable with gas, but I'm finding my paths.

The actual point is that I need listings to be generated, so that I can see
which bytes of machine code my macros generate. That's not enough, however,
since I can not read the machine code block-wise :-/ So I usually activate
macro expansion to see which actual line of the macros the generated code
responds to.

But I also have a bunch of macros that don't generate code at all, i. e. one
set of macros to check if a parameter passed to another macro is a number or
a register or a (possible) symbol.

Checking for a number is quite straight forward, though it can only be done
character by character using gas' scripting capabilities. So, checking for
a number like 99999 ends up in generating (macro expanded) lines like

  .ifc 9,0
  .ifc 9,1
  .ifc 9,2
  ...
  .ifc 9,9
   __is__digit=1

(No literal example, just made up, but you get the figure.)

Having those lines in the listing doesn't help anyone ;-) I don't care
about the disk space occupied, but about the readability of the listings.

I started playing with .list/.nolist (or rather, the other way around),
but that didn't lead me to anything usable. I think that the involved
code is somehow buggy. Though this should not be the topic of this mail,
I'll add some lines about it at the end (if I don't forget to).

I'm using a rather old (11.2) openSuse distribution, and had a reason to
get an build binutils from source to have gas 2.22 available, so I started
looking at the source and thought about introducing two new pseudo-ops,
which I called 'nomacexp' and 'macexp', which I added to the
  static const pseudo_typeS potable[] = { ... }
in read.c like this:

  {"macexp", s_macexp, 1},
  {"nomacexp", s_macexp, 0},
  
Then I added to read.c the appropriate function:

  void s_macexp (int on)
  {
    if (listing)
    {
      switch (on)
      {
	case 0:		// called when reading "nomacexp"
	  if ((listing & LISTING_MACEXP) == LISTING_MACEXP)
	    listing -= LISTING_MACEXP;
	  break;
	case 1:		// called when reading "macexp"
	  listing |= LISTING_MACEXP;
	  break;
	default:
	  abort ();
      }
    }
  }

which is modelled after listing_list() in listing.c, and prototyped it in
in read.h:

  extern void s_macexp (int);

I thought this would do it, since there is (was) only one occurrence of
checking against LISTING_MACEXP in the original source (line 644 in read.c,
eventually becoming line 666 ;-/ in my modified file):

  if ((listing & LISTING_MACEXP) && macro_nest > 0)

But this seems to be too late, since my modifications show no effect on the
listing output. I also must admit that I don't understand what "macro_nest"
is really for.

(BTW, did I ever mention that I'm not a C-er?)

The actual macro expansion, if I understand correctly, is done in macro.c,
namely in check_macro() by the help of macro_expand(), which in turn calls
macro_expand_body(). But macro.c doesn't share the read.c data entity
  int listing;
which is included by listing.c by
  extern int listing;
if I understand correctly.

So, the essence of my question is: where does the code decide whether or not
to actually expand a macro, or (this would be sufficient too) where is it
decided to emit the macro expansion to the listing file?

Though I'm not a C-er, I'm sure I could fix this if you could just tell me
where I had to put the distinction. Thanks in advance.


About the other topic: I think at least the documentation about .list/.nolist
is wrong/not appropriate. The info pages say

  These two directives maintain an internal counter (which is zero
  initially). `.list' increments the counter, and `.nolist' decrements
  it. Assembly listings are generated whenever the counter is greater
  than zero.

and

  By default, listings are disabled. When you enable them (with the
  `-a' command line option;  Command-Line Options Invoking.), the
  initial value of the listing counter is one.

I've included a ".nolist" directive at the beginning of each include file,
and a ".list" directive at the end of each. This worked.

Assuming the initial value is 1 (I let as generate listings for each and
every assembly), within all the include files (after ".nolist") the value
of the control variable is supposed to be 0.

I can't describe this in a few words, and I don't have the time to make
up a minimal (not) working example, but

  - if I use ".nolist" at the beginning of any one macro to suppress
    further listing of its expansion, it does not work;
  - if I use ".list" at the end of the respective macro, it does not
    reestablish the state as it was before the ".nolist" at the very
    beginning of the same macro.

When starting to examine gas' source code, I've concentrated on this issue
first, finding in 
  static const pseudo_typeS potable[] = { ... }
in read.c:

  {"list", listing_list, 1},	/* Turn listing on.  */
  {"nolist", listing_list, 0},	/* Turn listing off.  */

with listing_list() in listing.c being

  void
  listing_list (int on)
  {
    if (listing)
    {
      switch (on)
      {
	case 0:		// called when reading "nolist"
	  if (listing_tail->edict == EDICT_LIST)
	    listing_tail->edict = EDICT_NONE;
	  else
	    listing_tail->edict = EDICT_NOLIST;
	  break;
	case 1:		// called when reading "list"
	  if (listing_tail->edict == EDICT_NOLIST
	      || listing_tail->edict == EDICT_NOLIST_NEXT)
	    listing_tail->edict = EDICT_NONE;
	  else
	    listing_tail->edict = EDICT_LIST;
	  break;
	case 2:
	  listing_tail->edict = EDICT_NOLIST_NEXT;
	  break;
	default:
	  abort ();
      }
    }
  }

(Just changed (part of) the indentation.)

This is not what I call to "maintain an internal counter", as quoted above.
There is a (non-static)

  int show_listing = 1;

in listing_listing() in listing.c, which also holds these following lines:

  list_line = list->line;
  switch (list->edict)
  {
    case EDICT_LIST:
      /* Skip all lines up to the current.  */
      list_line--;
      break;
    case EDICT_NOLIST:
      show_listing--;
      break;
    case EDICT_NOLIST_NEXT:
      if (show_listing == 0)
      list_line--;
      break;
   ...
  }
  ...

  if (list->edict == EDICT_LIST
    || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0))
  {
    /* Enable listing for the single line that caused the enable.  */
    list_line++;
    show_listing++;
  }

(Indentation modified.)

Especially the "case EDICT_LIST:" in combination with the later "if ..."
makes me sceptic, though I admit that I don't completely understand the
expressed logic.

Besides that I don't see how show_listing and list_line correspond to each
other and EDICT_LIST, EDICT_NOLIST, EDICT_NOLIST_NEXT, and EDICT_NONE, the
main point of my scepticism and my assumption that the code is buggy comes
from the fact (shortly) stated now.

(I'm sorry that I can't provide you with the full source code and that I
don't have the time to make up a minimal (not) working example.)

In the first file ever included in my assembly source, I have put the
sequence

  .rept 1000
  .nolist
  .endr

which made my listing file cute 2247 bytes in size. All there was, was the
header, the first include, then the symbol table. Using binary search I
could quickly determine that the result was the same with a repetition
count of 264, but with that of 263, the size was 3372... 

After the initial include it showed part of macro expansion, but just
starting in the very middle of it. Using a repeat count of 262, it showed
just a few lines more of that same macro, but still beginning at a point
that had nothing to do with another .list/.nolist directive.

Just now I'm seeing that I can't reproduce this behaviour, but what...
this is just an aside topic. Once I find more time, I will try to get back
to those results of yesterday, then submit a "real" bug report.

In the meantime, I will just hope for a hintful answer regarding the actual
question asked above... Thanks in advance,

Jagged

----- End forwarded message -----

-- 
 /¯\ ASCII RIBBON CAMPAIGN |  I believe  in  spon-  | _   _   O  ___ ___
 \ /   NO HTML IN E-MAIL   |  taneous  combustion,  | ¯\ /¯\ /¯\ ¯|¯ |¯¯
  X    AND USENET-GROUPS   |  not in instant email  | _/ | _ |_|  |  |-
 / \  www.asciiribbon.org  |  replies...            | ¯\ \_/ |¯|  |  |__ o o o

Attachment: pgp00000.pgp
Description: PGP signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]