.bundle_align_mode 32
nop
read.c:776:26: runtime error: shift exponent 32 is too large for
32-bit type 'unsigned int'
Avoid this by using wider types in the expressions.
asan complains when running the gas all/cond-diag test.
* read.c (deferred_diag_head, deferred_diag_tail): Renamed
from deferred_diags and last_deferred_diag, making the tail
pointer a deferred_diag**.
(s_errwarn_if): Simplify appending to list. Free unused diag
on error.
(evaluate_deferred_diags): Free list.
Calls to md_number_to_chars don't need to cast their value arg (*).
Remove those casts. avr_output_property_recode made a call to
md_number_to_chars with size of 1. Simplify that. tc-bpf.c
md_convert_frag used write_insn_bytes that simply copied input to
output. Dispense with that nonsense, and similarly in a couple of
other places where md_number_to_chars was called with size 1.
*) unless the value arg is an expression that needs a cast, eg. tic54x
emit_insn where the shift left could trigger signed overflow UB
without a cast.
This removes many unnecessary NULL casts. I'm also adding a few arg
casts in concat calls, to make the code consistent. Advice from quite
a few years ago was that it's better to use the exact type for args
corresponding to function ellipses, in case NULL is defined as plain
0. (I think that happened with some early 64-bit systems. Plain NULL
ought to be OK nowadays.)
Many frag_var calls have unnecessary casts on arguments, no doubt from
the days when binutils was written for K&R C. (ie. functions were not
prototyped so you needed to cast anything that didn't match the
expected type after default promotions, as you still do for args
matching a function ellipsis.) Remove those casts.
* config/tc-alpha.c (s_alpha_comm): Use offset_T for cur_size
to avoid need for casts. Remove casts from frag_var args.
* config/tc-ia64.c (obj_elf_vms_common): Remove casts from
frag_var args.
* config/tc-m32r.c (m32r_scomm): Likewise.
* config/tc-m68hc11.c (build_jump_insn): Likewise.
(build_dbranch_insn): Likewise.
* config/tc-m68k.c (md_assemble): Likewise.
* config/tc-microblaze.c (microblaze_s_lcomm): Likewise.
* config/tc-mmix.c (s_loc): Likewise.
* config/tc-ppc.c (ppc_elf_lcomm, ppc_comm): Likewise.
* config/tc-score.c (s3_s_score_lcomm): Likewise.
* config/tc-score7.c (s7_s_score_lcomm): Likewise.
* config/tc-sh.c (sh_cons_align): Likewise.
* config/tc-sparc.c (s_reserve, s_common): Likewise.
(sparc_cons_align): Likewise.
* config/tc-tic4x.c (tic4x_seg_alloc, tic4x_bss): Likewise.
* config/tc-tic54x.c (tic54x_bss, tic54x_space): Likewise.
(tic54x_usect, tic54x_field): Likewise.
* config/tc-tic6x.c (s_tic6x_scomm): Likewise.
* config/tc-v850.c (v850_offset, v850_comm): Likewise.
* frags.c (frag_align, frag_align_pattern, frag_align_code): Likewise.
* gen-sframe.c (output_sframe_row_entry): Likewise.
(output_sframe_funcdesc): Likewise.
* read.c (s_fill, do_org, s_space, emit_leb128_expr): Likewise.
* symbols.c (colon)): Likewise.
oss-fuzz managed to trigger this assert, by assembling directives in
the absolute section. Avoid this using similar code to that in
frags.c:frag_new (commit 2dc2dfa7d7).
Rather than having people resort to indirect means to issue a certain
kind of diagnostic conditionally upon an expression which can (or
should) only be evaluated when all sections were sized and all symbols
had their final values established, provide directives to directly
achieve this.
Both callers, despite spelling things differently, now pass the same
input for its 2nd parameter. Therefore, as was supposed to be the case
anyway, this 2nd parameter isn't needed anymore - the function can
calculate "sign" all by itself from the incoming expression. Instead
make the function return the resulting value, for emit_expr_with_reloc()
to consume for setting its "extra_digit" local variable.
Interestingly emit_leb128_expr() already assumes X_unsigned is properly
set for O_big. Adjust its conversion-to-bignum to respect the incoming
flag, and have convert_to_bignum() correctly set it on output.
It further can't be quite right that convert_to_bignum() depends on
anything other than the incoming expression. Therefore adjust
emit_expr_with_reloc() to be in line with the other invocation.
This also requires an adjustment for SH, which really should have been
part of 762acf217c ("gas: maintain O_constant signedness in more
cases").
On x86, MAX_MEM_FOR_RS_ALIGN_CODE is 35, when the most common
alignment is 2**3 or 2**4, where the max memory required for the
alignment nops is 7 and 15 bytes respectively. So there is some
memory wasted since commit 83d94ae428. It's not a large amount,
especially considering that frag overhead on x86_46 is 144 bytes,
but even so I'd rather not be blamed for increasing gas memory usage.
So to reduce the memory we'd like to take the alignment into
consideration when initialising an rs_align_code frag. The only
difficulty here is start_bundle making an rs_align_code frag with an
alignment of zero initially, then later increasing the alignment. We
change that to use the bundle alignment when setting up the frag. I
think that is sufficient as bundle_align_p2 can't change in the middle
of a start_bundle/finish_bundle sequence.
I haven't modified any targets other than x86 in this patch. Most
won't benefit much due to using fairly small MAX_MEM_FOR_RS_ALIGN_CODE.
* read.c (start_bundle): Create rs_align_code frag with
bundle_align_p2 alignment, then set to zero alignment.
(finish_bundle): Adjust comment.
* frags.c (MAX_MEM_FOR_RS_ALIGN_CODE): Pass p2align and max
to macro.
* config/tc-i386.h (HANDLE_ALIGN): Assert that max_bytes is
sufficient for nop padding.
(max_mem_for_rs_align_code): New inline function.
(MAX_MEM_FOR_RS_ALIGN_CODE): Use it.
* config/tc-aarch64.h: Adjust MAX_MEM_FOR_RS_ALIGN_CODE.
* config/tc-alpha.h: Likewise.
* config/tc-arc.h: Likewise.
* config/tc-arm.h: Likewise.
* config/tc-epiphany.h: Likewise.
* config/tc-frv.h: Likewise.
* config/tc-ia64.h: Likewise.
* config/tc-kvx.h: Likewise.
* config/tc-loongarch.h: Likewise.
* config/tc-m32r.h: Likewise.
* config/tc-metag.h: Likewise.
* config/tc-mips.h: Likewise.
* config/tc-nds32.h: Likewise.
* config/tc-ppc.h: Likewise.
* config/tc-riscv.h: Likewise.
* config/tc-rl78.h: Likewise.
* config/tc-rx.h: Likewise.
* config/tc-score.h: Likewise.
* config/tc-sh.h: Likewise.
* config/tc-sparc.h: Likewise.
* config/tc-spu.h: Likewise.
* config/tc-tilegx.h: Likewise.
* config/tc-tilepro.h: Likewise.
* config/tc-visium.h: Likewise.
* config/tc-xtensa.h: Likewise.
Make rs_fill_nop behave like rs_fill in using a repeat count
(fr_offset) to emit fr_var length repeated nop patterns. Besides
being more elegant, this reduces memory required for large .nops
directives.
* as.h (rs_fill_nop): Update comment.
* config/tc-i386.c (i386_generate_nops): Handle rs_fill_nop as
for rs_align_code.
* config/tc-i386.h (MAX_MEM_FOR_RS_SPACE_NOP): Define.
* listing.c (calc_hex): Handle rs_fill_nop as for rs_fill.
* read.c (MAX_MEM_FOR_RS_SPACE_NOP): Define.
(s_nops): Use MAX_MEM_FOR_RS_SPACE_NOP setting up frag.
* write.c (write_contents): Call md_generate_nops for rs_fill_nop
before the fr_fix part is written, so that rs_fill_nop can be
handled as for rs_fill.
Now that rs_align_code has been corrected for all targets, put the
.align limit back to bits_per_address-1. Also fix a comment.
* frags.h (fr_var): Correct comment.
* read.c (TC_ALIGN_LIMIT): Revert commit ff4c03516c change.
Silence ubsan warning. We don't worry about wrap-around in most
places that adjust abs_section_offset, so don't fuss over an overflow
in the multiplication here.
* read.c (s_fill): Replace "long" vars with offsetT and valueT.
Avoid signed overflow calculating abs_section_offset.
At the moment we allow alignment of up to half the address space,
which is stupidly large and results in OOM on x86_64. Change that to
1G alignment in text sections. Also fix the warning message on
exceeding max allowed alignment.
* read.c (TC_ALIGN_LIMIT): Limit to 30 in text sections.
(s_align): Correct "alignment too large" value.
In 344b1e0f5f ("gas: range-check 3rd argument of .align et al") I
neglected to consider compilers which warn about signed/unsigned
mismatches in comparisons (which is somewhat odd when the signed value is
already known to be non-negative).
Negative values would have been silently converted to large positive
ones, which may not be the user's intention. Similarly overly large
values would have been silently truncated. Warn them instead, and zap
such values.
Ignoring return values often isn't a good idea. The Sparc assembler in
particular would report an internal error if an expression with
relocation specifier is used with .cfi_escape, when the same works fine
with .byte. Propagate the relocation indicator up from
do_parse_cons_expression(), and eventually into emit_expr_with_reloc().
dot_cfi_fde_data(), only retaining the expression's X_add_number, would
require further work. Simply report the lack of support there. While
there, also check that what we were dealt is actually a constant.
Repeat counts greater than 1 will emit data directly into the current
(sub-)section. That's wrong with .cfi_*, which defer data emission until
much later: N-1 instances of the specified data would not end up in
.eh_frame (or whatever the section that CFI data was specified to go
into). Simply disallow "repeat" expressions in such cases.
Besides it being somewhat off to have three decls scattered across the
code base, it is generally bad practice for the definition of a symbol
to not also observe its declaration (making sure the two won't go out of
sync).
PR gas/32721
In this bogus piece of code distilled from fuzzing and slightly edited:
A=%eax|%!
Y=A
Z=A
or $6,Z
the first of the equates with A on the rhs changes A's section (due to
the use of S_GET_VALUE()), from expression to register, thus yielding Y
in the expression section (and X_op being O_symbol), but Z in the
register section (and X_op being O_register with X_add_value being -1).
There shouldn't be random O_register expressions, though, for targets
setting md_register_arithmetic to false. Plus both Y and Z would better
be exchangeable.
In pseudo_set() wire handling of O_symbol expressions referencing a
symbol in the expression section to that of other stuff ending up in
this section.
Also avoid bogus O_register expressions to be created, for targets
setting md_register_arithmetic to false: S_GET_VALUE() would resolve
any arithmetic, which must not happen for such targets. To be on the
safe side for such targets, also amend resolve_register(). Correct
another earlier oversight there too (affecting at least Z80), by using
the new expr_copy() helper there as well.
Undo 46b9f07dfe ("PR 32721, internal error in
tc-i386.c:parse_register"), albeit without losing the simplification it
did.
... by way of introducing LEX_EOL and LEX_EOS. As a prereq convert the
remaining open-coded accesses.
The Alpha change is actually a functional one: The array slot for '!'
having been set to 1 is very unlikely to have been correct. 1 means "end
of line", when surely "end of statement" was always meant.
Let's extend lex_type[] to also cover whitespace, then having a simple
macro to uniformly recognize both blanks and tabs (and \r when it's not
EOL) as such.
In macro.c use sb_skip_white() as appropriate, instead of open-coding
it.
... by purging dot_{frag,value}. Right now these two and dot_symbol are
updated independently, which can't be quite right. Centralize .-related
information in dot_symbol, updating it also where previously
dot_{frag,value} were updated. Since S_GET_VALUE() can't be used to
retrieve what used to be dot_value, introduce a new helper to fetch both
frag and offset.
Deferring expression evaluation is often necessary. However, the value
current_location() records typically is intended to represent the
location at the point of use of the expression, with the exception being
.eqv (or its == equivalent). Change how expr_defer behaves in this
regard, and introduce a special mode just for pseudo_set() to use.
Introduce a predicate to cover both "deferred" modes, and use it
everywhere except in current_location(), where only the new mode wants
checking for.
There is a test in do_repeat to error on "negative" repeat counts.
Just at what value a ssize_t is negative of course depends on the
host. Change the excessive repeat count to a fixed value, 0x80000000,
ie. what would be seen as negative on a 32-bit host.
Put these on the notes obstack too.
* config/tc-wasm32.c (wasm32_leb128): Use notes_alloc for
reloc_list vars.
* read.c (s_reloc): Likewise.
* write.c (create_note_reloc): Likewise.
(write_object_file): Reset reloc_list after write_relocs.
This is the first of a series of patches aimed at making it possible
to configure with CFLAGS="-g -O2 -fsanitize=address,undefined" and run
the binutils and gas testsuite on x86_64-linux without using
ASAN_OPTIONS=detect_leaks=0. ie. the patch series is aimed at fixing
common gas, ar, objcopy, objdump, and readelf leaks.
* config/tc-tic54x.c (md_begin): Make use of notes_strdup rather
than xstrdup to copy entries added to include_dirs.
* read.c (read_end): Free include_dirs array.
Add .cv_ucomp and .cv_scomp pseudo-directives for object files for
Windows targets, which encode compressed CodeView integers according to
the algorithm in CVCompressData in
https://github.com/Microsoft/microsoft-pdb/blob/master/include/cvinfo.h.
This is essentially Microsoft's answer to the LEB128, though used in far
fewer places.
CodeView uses these to encode the "binary annotations" in the
S_INLINESITE symbol, which express the relationship between code offsets
and line numbers in inlined functions. This has to be done in the
assembler as GCC doesn't know how many bytes each instruction takes up.
There's no equivalent for this for MSVC or LLVM, as in both cases the
assembler and compiler are integrated.
.cv_ucomp represents an unsigned big-endian integer between 0 and 0x1fffffff,
taking up 1, 2, or 4 bytes:
Value between 0 and 0x7f:
0aaaaaaa -> 0aaaaaaa (identity-mapped)
Value between 0x80 and 0x3fff:
00aaaaaa bbbbbbbb -> 10aaaaaa bbbbbbbb
Value between 0x4000 and 0x1fffffff:
000aaaaa bbbbbbbb ccccccccc dddddddd ->
110aaaaa bbbbbbbb ccccccccc dddddddd
.cv_scomp represents a signed big-endian integer between -0xfffffff and
0xfffffff, encoded according to EncodeSignedInt32 in cvinfo.h. The
absolute value of the integer is shifted left one bit, the LSB set
for a negative value, and the result expressed as if it were a
.cv_ucomp: cv_scomp(x) = cv_ucomp((abs(x) << 1) | (x < 0 ? 1 : 0))
Maintaining line numbers correctly both inside the region and past it
requires special care. The SB produced there is somewhat different from
that produced for e.g. macro expansions, and hence also needs treating
differently: In particular we aren't doing anything resembling macro
expansion here.
The new testcase may be a little misplaced in macros/, but that's where
all the other #APP / #NO_APP ones are.
For one '#' may not be in line_comment_chars[] in the first place. Look
for just it when it is (these "directives" are akin to C preprocessor
directives after all), but accept any other line comment character
otherwise (in read.c further requiring a match on the counterpart
"directive").
Then, when in the middle of a file, the constructs should be all on
their own on a line. There needs to be a newline ahead of them and
after them.
Finally '\n' may not be the only end-of-line character. Accept any (but
not end-of-statement ones) in read.c, while making sure in input-file.c
there is one in the first place - merely any kind of whitespace isn't
good enough.
It's not valid to recognize it after mere line separators (often
semicolon) or after labels, let alone after tc_unrecognized_line()
perhaps having parsed off parts of a line. It shouldn't even be
preceded by whitespace, aiui.
However, keep ignoring line comments as before, for backwards
compatibility.
Internal naming of functions / data as well as commentary mixes lines
and statements. It is presumably this confusion which has led to the
wrong use of ignore_rest_of_line() when dealing with line comments in
read_a_source_file(). We shall not (silently) produce different output
depending on whether -f is passed (for suitable input).
Introduce two new helper macros, intended to be used in favor of open-
coded accesses to is_end_of_line[]. To emphasize the difference, convert
ignore_rest_of_line() right away, including adjustments to its comments.
Since most targets have # in line_comment_chars[], add a target-
independent test for that, plus an x86-only one also checking for non-#
to work as intended.
... for the purposes of get_line_sb() and _find_end_of_line(): They
support \@ just like macros do, and hence the special casing there also
needs applying.
PR gas/31903
While elsewhere having realized that "one" doesn't point to a nul-
terminated string, it somehow didn't occur to me that the pre-existing
strstr() could have been wrong, and hence I blindly added a new use of
the function. Add the (already prior to 1e3c814459 ["gas: extend \+
support to .rept"]) missing call to sb_terminate(), leveraging that to
simplify the other two places where the lack of nul termination was
previously worked around.