LoongArch: add .option directive

In some cases we may want to use different options only for certain
assembly, so the .option directive is added to control the assembler
options.

.option can accept 4 parameters:

push
pop
  Pushes or pops the current option stack. They limit the scope of
  option changes so that they do not affect other parts of the assembly
  file.

relax
norelax
  Enables or disables relaxation.
This commit is contained in:
Lulu Cai 2024-05-21 10:14:27 +08:00 committed by liuzhensong
parent 6a4f078b5b
commit 8864c4afdf
6 changed files with 119 additions and 0 deletions

View File

@ -541,6 +541,64 @@ s_dtprel (int bytes)
demand_empty_rest_of_line ();
}
struct LARCH_option_stack
{
struct LARCH_option_stack *next;
struct loongarch_ASEs_option options;
};
static struct LARCH_option_stack *LARCH_opts_stack = NULL;
/* Handle the .option pseudo-op.
The alignment of .align is done by R_LARCH_ALIGN at link time.
If the .align directive is within the range controlled by
.option norelax, that is, relax is turned off, R_LARCH_ALIGN
cannot be generated, which may cause ld to be unable to handle
the alignment. */
static void
s_loongarch_option (int x ATTRIBUTE_UNUSED)
{
char *name = input_line_pointer, ch;
while (!is_end_of_line[(unsigned char) *input_line_pointer])
++input_line_pointer;
ch = *input_line_pointer;
*input_line_pointer = '\0';
if (strcmp (name, "relax") == 0)
LARCH_opts.relax = 1;
else if (strcmp (name, "norelax") == 0)
LARCH_opts.relax = 0;
else if (strcmp (name, "push") == 0)
{
struct LARCH_option_stack *s;
s = XNEW (struct LARCH_option_stack);
s->next = LARCH_opts_stack;
s->options = LARCH_opts;
LARCH_opts_stack = s;
}
else if (strcmp (name, "pop") == 0)
{
struct LARCH_option_stack *s;
s = LARCH_opts_stack;
if (s == NULL)
as_bad (_(".option pop with no .option push"));
else
{
LARCH_opts_stack = s->next;
LARCH_opts = s->options;
free (s);
}
}
else
{
as_warn (_("unrecognized .option directive: %s"), name);
}
*input_line_pointer = ch;
demand_empty_rest_of_line ();
}
static const pseudo_typeS loongarch_pseudo_table[] =
{
{ "dword", cons, 8 },
@ -548,6 +606,7 @@ static const pseudo_typeS loongarch_pseudo_table[] =
{ "half", cons, 2 },
{ "dtprelword", s_dtprel, 4 },
{ "dtpreldword", s_dtprel, 8 },
{ "option", s_loongarch_option, 0},
{ NULL, NULL, 0 },
};

View File

@ -35,5 +35,6 @@ if [istarget loongarch*-*-*] {
if [istarget loongarch64-*-*] {
run_list_test "illegal-operand"
run_list_test "pseudo_op_option_fail"
}
}

View File

@ -0,0 +1,36 @@
#as: -mrelax
#objdump: -dr
#skip: loongarch32-*-*
.*: file format .*
Disassembly of section .text:
0.* <.text>:
0: 1a000004 pcalau12i \$a0, 0
0: R_LARCH_PCALA_HI20 x
0: R_LARCH_RELAX \*ABS\*
4: 02c00084 addi.d \$a0, \$a0, 0
4: R_LARCH_PCALA_LO12 x
4: R_LARCH_RELAX \*ABS\*
8: 1a000004 pcalau12i \$a0, 0
8: R_LARCH_PCALA_HI20 x
c: 02c00084 addi.d \$a0, \$a0, 0
c: R_LARCH_PCALA_LO12 x
10: 1a000004 pcalau12i \$a0, 0
10: R_LARCH_PCALA_HI20 x
10: R_LARCH_RELAX \*ABS\*
14: 02c00084 addi.d \$a0, \$a0, 0
14: R_LARCH_PCALA_LO12 x
14: R_LARCH_RELAX \*ABS\*
18: 1a000004 pcalau12i \$a0, 0
18: R_LARCH_PCALA_HI20 x
1c: 02c00084 addi.d \$a0, \$a0, 0
1c: R_LARCH_PCALA_LO12 x
20: 1a000004 pcalau12i \$a0, 0
20: R_LARCH_PCALA_HI20 x
20: R_LARCH_RELAX \*ABS\*
24: 02c00084 addi.d \$a0, \$a0, 0
24: R_LARCH_PCALA_LO12 x
24: R_LARCH_RELAX \*ABS\*

View File

@ -0,0 +1,19 @@
# Gas enables relax by default.
# Push and pop can be nested, and each pop restores the options before
# the most recent push.
.text
.L1:
la.pcrel $a0,x
.option push
.option norelax
la.pcrel $a0,x
.option push
.option relax
la.pcrel $a0,x
.option pop
la.pcrel $a0,x
.option pop
la.pcrel $a0,x

View File

@ -0,0 +1,2 @@
.*: Assembler messages:
.*: Error: \.option pop with no \.option push

View File

@ -0,0 +1,2 @@
.text
.option pop