azp:44% cat h.s .data msg: .asciz "hello world.\n" msglen = .-msg-1 msglen=msglen & 0xff azp:45% as -a h.s -o h.o h.s: Assembler messages: h.s:5: Error: symbol definition loop encountered at `msglen' h.s:5: Error: undefined symbol `msglen' in operation setting `msglen' h.s:5: Internal error, aborting at /usr/src/gnu/usr.bin/binutils/as/i386-freebsd/../../../../../contrib/binutils/gas/symbols.c line 1166 in resolve_symbol_value Please report this bug. azp:46% as h.s -o h.o Interesting that it doesn't crash with -a flag.
This is a consequence of the way gas resolves symbols. The problem is that the first assignment to msglen isn't resolved immediately when parts of the expression use symbols ("." and "msg" here) in different frags. A frag is a chunk of code/data being assembled, with a fixed part and a variable part. Because gas knows that frags might have a variable part, it leaves such expressions for later evaluation, after all frags have their variable parts fixed. Thus the second assignment to msglen also can't be evaluated immediately, and gas simply sets the value of msglen to "msglen & 0xff", exactly as would be done if the first assignment had never been encountered. Which results in a symbol definition loop. The reason that -a causes the failure is that turning on listings employs a hack where a frag is allocated for each line. However, this can happen without -a if a new frag is needed for some other reason. I see a number of possible solutions, all of which I'm disinclined to implement myself. 1) Rewrite gas listing code to do without frags, possibly combined with 2) Modify gas symbol evaluation code to allow immediate subtraction of symbols in different frags if all intervening frags are fixed in size. 3) Have gas generate multiple versions of symbols. (3) is probably the easiest to implement. You can do it yourself at the user level, of course: msg: .asciz "hello world.\n" x = .-msg-1 msglen=x & 0xff
Subject: Re: invalid error messages, and internal error abort That explains why the problem also affects things like: .if xlen & 1 /* is length odd? */ fails. It looks to me like the evaluation should be forced at the point that the value is needed, such as the .if mentioned here, the pushl $xlen, the foo=foo&3 --if it cannot be evaluated then, it is either an error or a 32 bit value. As for -a causing the different push instruction being used, this is a particularly annoying problem, as it is a perfectly reasonable thing to assemble a program with a listing to find where it failed running the binary from a previous assemble. It is also desirable for a binary built for production (with an assembly listing for documentation) to generate optimal code. Alan
http://sources.redhat.com/ml/binutils-cvs/2006-04/msg00013.html
http://sources.redhat.com/ml/binutils-cvs/2006-04/msg00028.html