LoongArch: Add -mignore-start-align option

Ignore .align at the start of a section may result in misalignment when
partial linking. Manually add -mignore-start-align option without partial
linking.

Gcc -falign-functions add .align 5 to the start of a section, it causes some
error message mismatch. Set these testcases to xfail on LoongArch target.
This commit is contained in:
mengqinggang
2024-04-07 16:34:42 +08:00
committed by liuzhensong
parent 02fa4bbec1
commit 20eee7540b
11 changed files with 96 additions and 24 deletions

View File

@@ -139,15 +139,17 @@ enum options
OPTION_ABI,
OPTION_FLOAT_ABI,
OPTION_FLOAT_ISA,
OPTION_LA_LOCAL_WITH_ABS,
OPTION_LA_GLOBAL_WITH_PCREL,
OPTION_LA_GLOBAL_WITH_ABS,
OPTION_RELAX,
OPTION_NO_RELAX,
OPTION_THIN_ADD_SUB,
OPTION_IGNORE_START_ALIGN,
OPTION_END_OF_ENUM,
};
@@ -165,6 +167,7 @@ struct option md_longopts[] =
{ "mrelax", no_argument, NULL, OPTION_RELAX },
{ "mno-relax", no_argument, NULL, OPTION_NO_RELAX },
{ "mthin-add-sub", no_argument, NULL, OPTION_THIN_ADD_SUB},
{ "mignore-start-align", no_argument, NULL, OPTION_IGNORE_START_ALIGN},
{ NULL, no_argument, NULL, 0 }
};
@@ -247,6 +250,10 @@ md_parse_option (int c, const char *arg)
LARCH_opts.thin_add_sub = 1;
break;
case OPTION_IGNORE_START_ALIGN:
LARCH_opts.ignore_start_align = 1;
break;
case OPTION_IGNORE:
break;
@@ -1772,7 +1779,9 @@ md_show_usage (FILE *stream)
-mthin-add-sub Convert a pair of R_LARCH_ADD32/64 and R_LARCH_SUB32/64 to\n\
R_LARCH_32/64_PCREL as much as possible\n\
The option does not affect the generation of R_LARCH_32_PCREL\n\
relocations in .eh_frame\n"));
relocations in .eh_frame\n\
-mignore-start-align Ignore .align if it is at the start of a section. This option\n\
can't be used when partial linking (ld -r).\n"));
}
static void
@@ -1794,39 +1803,60 @@ bool
loongarch_frag_align_code (int n, int max)
{
char *nops;
expressionS ex;
symbolS *s = NULL;
bfd_vma insn_alignment = 4;
bfd_vma bytes = (bfd_vma) 1 << n;
bfd_vma worst_case_bytes = bytes - insn_alignment;
/* If we are moving to a smaller alignment than the instruction size, then no
alignment is required. */
if (bytes <= insn_alignment)
return true;
/* When not relaxing, loongarch_handle_align handles code alignment. */
if (!LARCH_opts.relax)
return false;
bfd_vma align_bytes = (bfd_vma) 1 << n;
bfd_vma worst_case_bytes = align_bytes - 4;
bfd_vma addend = worst_case_bytes;
bool align_max = max > 0 && (bfd_vma) max < worst_case_bytes;
/* If we are moving to a smaller alignment than the instruction size, then no
alignment is required. */
if (align_bytes <= 4)
return true;
/* If max <= 0, ignore max.
If max >= worst_case_bytes, max has no effect.
Similar to gas/write.c relax_segment function rs_align_code case:
if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype). */
if (max > 0 && (bfd_vma) max < worst_case_bytes)
if (align_max)
{
s = symbol_find (now_seg->name);
worst_case_bytes = ALIGN_MAX_ADDEND (n, max);
addend = ALIGN_MAX_ADDEND (n, max);
}
frag_grow (worst_case_bytes);
/* Use relaxable frag for .align.
If .align at the start of section, do nothing. Section alignment can
ensure correct alignment.
If .align is not at the start of a section, reserve NOP instructions
and R_LARCH_ALIGN relocation. */
nops = frag_var (rs_machine_dependent, worst_case_bytes, worst_case_bytes,
rs_align_code, s, worst_case_bytes, NULL);
if (LARCH_opts.ignore_start_align)
{
frag_grow (worst_case_bytes);
/* Use relaxable frag for .align.
If .align at the start of section, do nothing. Section alignment can
ensure correct alignment.
If .align is not at the start of a section, reserve NOP instructions
and R_LARCH_ALIGN relocation. */
nops = frag_var (rs_machine_dependent, worst_case_bytes, worst_case_bytes,
rs_align_code, s, addend, NULL);
}
else
{
nops = frag_more (worst_case_bytes);
if (align_max)
{
ex.X_add_symbol = s;
ex.X_op = O_symbol;
}
else
ex.X_op = O_constant;
ex.X_add_number = addend;
fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
&ex, false, BFD_RELOC_LARCH_ALIGN);
}
/* Default write NOP for aligned bytes. */
loongarch_make_nops (nops, worst_case_bytes);

View File

@@ -1,4 +1,4 @@
#as:
#as: -mignore-start-align
#objdump: -dr
.*:[ ]+file format .*

View File

@@ -256,6 +256,7 @@ dec2 : [1-9][0-9]?
int relax;
int thin_add_sub;
int ignore_start_align;
} LARCH_opts;
extern size_t loongarch_insn_length (insn_t insn);

View File

@@ -52,6 +52,9 @@ set build_tests {
{"DWARF parse during linker error"
"" "-fno-toplevel-reorder"
{dwarf2a.c dwarf2b.c} {{error_output "dwarf2.err"}} "dwarf2.x"}
}
set build_tests_dwarf3 {
{"Handle no DWARF information"
"" "-g0"
{dwarf3.c} {{error_output "dwarf3.err"}} "dwarf3.x"}
@@ -72,6 +75,8 @@ set run_tests {
set old_CFLAGS "$CFLAGS_FOR_TARGET"
append CFLAGS_FOR_TARGET " $NOSANITIZE_CFLAGS"
run_cc_link_tests $build_tests
setup_xfail loongarch*-*-*
run_cc_link_tests $build_tests_dwarf3
run_ld_link_exec_tests $run_tests
set CFLAGS_FOR_TARGET "$old_CFLAGS"

View File

@@ -0,0 +1,2 @@
.text
la.local $t0, .text

View File

@@ -0,0 +1,3 @@
.text
.align 4
ret

View File

@@ -1,3 +1,4 @@
#as: -mignore-start-align
#ld: -e0
#objdump: -d

View File

@@ -19,10 +19,38 @@
# MA 02110-1301, USA.
#
if [istarget loongarch64-*-*] {
run_dump_test "relax-align-first"
proc run_partial_linking_align_test {} {
global as
global ld
global srcdir
global subdir
global runtests
set testname "partial-link-align"
if ![runtest_file_p $runtests $testname] then {
return
}
if { ![ld_assemble $as "$srcdir/$subdir/$testname-a.s" tmpdir/a.o]
|| ![ld_assemble $as "$srcdir/$subdir/$testname-b.s" tmpdir/b.o]
|| ![ld_link $ld tmpdir/$testname.os "tmpdir/a.o tmpdir/b.o -r"]
|| ![ld_link $ld tmpdir/$testname "tmpdir/$testname.os -e0 -Ttext 0x1000"] } {
fail $testname
} else {
set objdump_output [run_host_cmd "objdump" "-d tmpdir/$testname"]
if { [ regexp ".*1010:\\s*4c000020\\s*jirl.*" $objdump_output ] } {
pass $testname
} else {
fail $testname
}
}
}
if [istarget loongarch64-*-*] {
if [isbuild loongarch64-*-*] {
run_dump_test "relax-align-ignore-start"
run_partial_linking_align_test
set testname "loongarch relax .exe build"
set pre_builds [list \
[list \

View File

@@ -74,6 +74,7 @@ if { ![check_compiler_available] } {
# in a literal pool outside the function, so that both the
# "undefined function" and "undefined line" tests fail.
setup_xfail xtensa*-*-linux*
setup_xfail loongarch*-*-*
set mf "tmpdir/undefined.o* in function `function':"
checkund $mf $testfn
@@ -154,6 +155,7 @@ if { ![check_compiler_available] } {
# eBPF doesn't support dwarf yet.
setup_xfail bpf-*-*
setup_xfail loongarch*-*-*
checkund $ml $testline
}