This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
RFA: gas-arm: maintain literal pools on a per section/per-subsection basis
- From: Nick Clifton <nickc at redhat dot com>
- To: binutils at sources dot redhat dot com
- Cc: brett dot w dot gaines at intel dot com, rearnshaw at cambridge dot arm dot com,Philip dot Blundell at pobox dot com
- Date: 26 Jul 2002 16:26:03 +0100
- Subject: RFA: gas-arm: maintain literal pools on a per section/per-subsection basis
Hi Guys,
Attached below is a patch that changes GAS for ARM so that it
maintains a separate literal pool for each section and each
subsection (if they are needed). This means that code like this:
.text 0
ldr r0, =message
.text 1
.ltorg @ dump sub-section 1 literals
message:
.asciz "Message"
.text 0
.ltorg @ dump sub-section 0 literals
table:
.space 4096
will assemble correctly instead of reporting:
Error: invalid literal constant: pool needs to be closer
The problem is that with the current code the literal pool
containing the address of 'message' is dumped at the start of
sub-section 1 of the .text section because of the first .ltorg
directive, instead of in the middle of sub-section 0 of .text
section, because of the second .ltorg directive. Since sub-section
1 is only emitted after the end of sub-section 0, and sub-section 0
has a great big '.space 4096' directive in it, the literal pool
is dumped too far away.
What might be controversial about this patch however, and the reason
why I am asking for comments first, is that it also changes the
default behavior of the assembler so that the literal pool is no
longer automatically dumped upon section change, but instead only
when a .ltorg directive is encountered, or at the end of input.
This makes more sense, since it allows the programmer complete
control over where the literal pools will be placed.
The old behavior - dumping literal pools on section change - can be
restored via a (new) command line switch -mimplicit-litpool-dump.
The reason for the old behavior was because of an attempt to be
compatible with ARM's assembler. The ARM assembler however, can
have only one occurrence of a section with a given name per source
file. Hence it only needs to maintain one literal pool and it knows
that it is safe to dump it as soon as a section change occurs. GAS,
on the other hand, allows multiple occurrences of a section within
a given source file and simply concatenates the contents from each
occurrence. Thus each section needs its own, independently
maintained literal pool.
So - any comments on, or objections to this patch ?
Cheers
Nick
2002-07-26 Nick Clifton <nickc@redhat.com>
* config/tc-arm.c (struct literal_pool): Add fields to allow
multiple literal pools to be maintained.
(dump_lit_pool_on_section_change): New variable.
(find_literal_pool): New function.
(find_or_make_literal_pool): New function.
(add_to_literal_pool): Use find_or_make_literal_pool.
(arm_s_text): Test dump_lit_pool_on_section_change.
(arm_s_data): Test dump_lit_pool_on_section_change.
(arm_s_section): Test dump_lit_pool_on_section_change.
(s_ltorg): Use find_literal_pool.
(arm_cleanup): Dump all literal pools.
(arm_opts[]): Add -mimplicit-litpool-dump and
-mno-implicit-litpool-dump.
* doc/c-arm.texi: Document -mimplicit-litpool-dump and
-mno-implicit-litpool-dump.
* doc/as.texinfo: Mention -mimplicit-litpool-dump and
-mno-implicit-litpool-dump.
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.124
diff -c -3 -p -w -r1.124 tc-arm.c
*** gas/config/tc-arm.c 8 Jun 2002 07:37:15 -0000 1.124
--- gas/config/tc-arm.c 26 Jul 2002 15:20:48 -0000
*************** const pseudo_typeS md_pseudo_table[] =
*** 2095,2101 ****
#ifdef OBJ_ELF
{ "word", s_arm_elf_cons, 4 },
{ "long", s_arm_elf_cons, 4 },
! { "file", dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
#else
{ "word", cons, 4},
--- 2095,2101 ----
#ifdef OBJ_ELF
{ "word", s_arm_elf_cons, 4 },
{ "long", s_arm_elf_cons, 4 },
! { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
#else
{ "word", cons, 4},
*************** static int arm_parse_fpu PARAMS ((char *
*** 2125,2197 ****
symbolS * last_label_seen;
static int label_is_thumb_function_name = false;
! /* Literal stuff. */
#define MAX_LITERAL_POOL_SIZE 1024
! typedef struct literalS
{
! struct expressionS exp;
! struct arm_it * inst;
! } literalT;
! literalT literals[MAX_LITERAL_POOL_SIZE];
! /* Next free entry in the pool. */
! int next_literal_pool_place = 0;
! /* Next literal pool number. */
! int lit_pool_num = 1;
! symbolS * current_poolP = NULL;
static int
add_to_lit_pool ()
{
! int lit_count = 0;
! if (current_poolP == NULL)
! current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section,
! (valueT) 0, &zero_address_frag);
! /* Check if this literal value is already in the pool: */
! while (lit_count < next_literal_pool_place)
{
! if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
! && inst.reloc.exp.X_op == O_constant
! && (literals[lit_count].exp.X_add_number
== inst.reloc.exp.X_add_number)
! && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned)
break;
! if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op
! && inst.reloc.exp.X_op == O_symbol
! && (literals[lit_count].exp.X_add_number
== inst.reloc.exp.X_add_number)
! && (literals[lit_count].exp.X_add_symbol
== inst.reloc.exp.X_add_symbol)
! && (literals[lit_count].exp.X_op_symbol
== inst.reloc.exp.X_op_symbol))
break;
-
- lit_count++;
}
! if (lit_count == next_literal_pool_place) /* New entry. */
{
! if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE)
{
! inst.error = _("literal pool overflow");
return FAIL;
}
! literals[next_literal_pool_place].exp = inst.reloc.exp;
! lit_count = next_literal_pool_place++;
}
inst.reloc.exp.X_op = O_symbol;
! inst.reloc.exp.X_add_number = (lit_count) * 4 - 8;
! inst.reloc.exp.X_add_symbol = current_poolP;
return SUCCESS;
}
--- 2125,2274 ----
symbolS * last_label_seen;
static int label_is_thumb_function_name = false;
! /* Literal Pool stuff. */
#define MAX_LITERAL_POOL_SIZE 1024
! /* Literal pool structure. Held on a per-section
! and per-sub-section basis. */
! typedef struct literal_pool
{
! expressionS literals [MAX_LITERAL_POOL_SIZE];
! unsigned int next_free_entry;
! unsigned int id;
! symbolS * symbol;
! segT section;
! subsegT sub_section;
! struct literal_pool * next;
! } literal_pool;
! /* Pointer to a linked list of literal pools. */
! literal_pool * list_of_pools = NULL;
! /* True if the current literal pool should automatically be dumped
! when a section change occurs. This is the default behaviour for
! older versions of arm-gas but newer versions only enable this
! via command line switch -mimplicit-litpool-dump. The new
! scheme allows the assembly programmer complete control over
! where the literal pools are place in the output.
! The reason for the old behavior (dumping the pool on section
! change) was because of an attempt to be compatible with ARM's
! own assembler. The ARM assembler however, can have only one
! occurence of a section with a given name per source file. Hence
! it only needs to maintain one literal pool and it knows that it
! is safe to dump it as soon as a section change occurs. GAS, on
! the other hand, allows multiple ocurrences of a section within
! a given source file and simply concatenates the contents from
! each ocurrence. Thus the placement of the literal pool needs
! to be under the control of the programmer, or happen automatically
! only at the end of the source file. */
! static int dump_lit_pool_on_section_change;
! static literal_pool * find_literal_pool PARAMS ((void));
! static literal_pool * find_or_make_literal_pool PARAMS ((void));
+ static literal_pool *
+ find_literal_pool ()
+ {
+ literal_pool * pool;
+
+ for (pool = list_of_pools; pool != NULL; pool = pool->next)
+ {
+ if (pool->section == now_seg
+ && pool->sub_section == now_subseg)
+ break;
+ }
+
+ return pool;
+ }
+
+ static literal_pool *
+ find_or_make_literal_pool ()
+ {
+ /* Next literal pool ID number. */
+ static unsigned int latest_pool_num = 1;
+ literal_pool * pool;
+
+ pool = find_literal_pool ();
+
+ if (pool == NULL)
+ {
+ /* Create a new pool. */
+ pool = (literal_pool *) xmalloc (sizeof (* pool));
+ if (! pool)
+ return NULL;
+
+ pool->next_free_entry = 0;
+ pool->section = now_seg;
+ pool->sub_section = now_subseg;
+ pool->next = list_of_pools;
+ pool->symbol = NULL;
+
+ /* Add it to the list. */
+ list_of_pools = pool;
+ }
+
+ /* New pools, and emptied pools, will have a NULL symbol. */
+ if (pool->symbol == NULL)
+ {
+ pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
+ (valueT) 0, &zero_address_frag);
+ pool->id = latest_pool_num ++;
+ }
+
+ /* Done. */
+ return pool;
+ }
+
+ /* Add the literal in the global 'inst'
+ structure to the relevent literal pool. */
static int
add_to_lit_pool ()
{
! literal_pool * pool;
! unsigned int entry;
! pool = find_or_make_literal_pool ();
! /* Check if this literal value is already in the pool. */
! for (entry = 0; entry < pool->next_free_entry; entry ++)
{
! if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
! && (inst.reloc.exp.X_op == O_constant)
! && (pool->literals[entry].X_add_number
== inst.reloc.exp.X_add_number)
! && (pool->literals[entry].X_unsigned
! == inst.reloc.exp.X_unsigned))
break;
! if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
! && (inst.reloc.exp.X_op == O_symbol)
! && (pool->literals[entry].X_add_number
== inst.reloc.exp.X_add_number)
! && (pool->literals[entry].X_add_symbol
== inst.reloc.exp.X_add_symbol)
! && (pool->literals[entry].X_op_symbol
== inst.reloc.exp.X_op_symbol))
break;
}
! /* Do we need to create a new entry? */
! if (entry == pool->next_free_entry)
{
! if (entry >= MAX_LITERAL_POOL_SIZE)
{
! inst.error = _("Literal Pool Overflow");
return FAIL;
}
! pool->literals[entry] = inst.reloc.exp;
! pool->next_free_entry += 1;
}
inst.reloc.exp.X_op = O_symbol;
! inst.reloc.exp.X_add_number = (entry) * 4 - 8;
! inst.reloc.exp.X_add_symbol = pool->symbol;
return SUCCESS;
}
*************** static void
*** 2353,2362 ****
s_ltorg (ignored)
int ignored ATTRIBUTE_UNUSED;
{
! int lit_count = 0;
char sym_name[20];
! if (current_poolP == NULL)
return;
/* Align pool as you have word accesses.
--- 2430,2443 ----
s_ltorg (ignored)
int ignored ATTRIBUTE_UNUSED;
{
! unsigned int entry;
! literal_pool * pool;
char sym_name[20];
! pool = find_literal_pool ();
! if (pool == NULL
! || pool->symbol == NULL
! || pool->next_free_entry == 0)
return;
/* Align pool as you have word accesses.
*************** s_ltorg (ignored)
*** 2366,2389 ****
record_alignment (now_seg, 2);
! sprintf (sym_name, "$$lit_\002%x", lit_pool_num++);
! symbol_locate (current_poolP, sym_name, now_seg,
(valueT) frag_now_fix (), frag_now);
! symbol_table_insert (current_poolP);
! ARM_SET_THUMB (current_poolP, thumb_mode);
#if defined OBJ_COFF || defined OBJ_ELF
! ARM_SET_INTERWORK (current_poolP, support_interwork);
#endif
! while (lit_count < next_literal_pool_place)
/* First output the expression in the instruction to the pool. */
! emit_expr (&(literals[lit_count++].exp), 4); /* .word */
! next_literal_pool_place = 0;
! current_poolP = NULL;
}
/* Same as s_align_ptwo but align 0 => align 2. */
--- 2447,2471 ----
record_alignment (now_seg, 2);
! sprintf (sym_name, "$$lit_\002%x", pool->id);
! symbol_locate (pool->symbol, sym_name, now_seg,
(valueT) frag_now_fix (), frag_now);
! symbol_table_insert (pool->symbol);
! ARM_SET_THUMB (pool->symbol, thumb_mode);
#if defined OBJ_COFF || defined OBJ_ELF
! ARM_SET_INTERWORK (pool->symbol, support_interwork);
#endif
! for (entry = 0; entry < pool->next_free_entry; entry ++)
/* First output the expression in the instruction to the pool. */
! emit_expr (&(pool->literals[entry]), 4); /* .word */
! /* Mark the pool as empty. */
! pool->next_free_entry = 0;
! pool->symbol = NULL;
}
/* Same as s_align_ptwo but align 0 => align 2. */
*************** static void
*** 2556,2562 ****
arm_s_text (ignore)
int ignore;
{
! if (now_seg != text_section)
s_ltorg (0);
#ifdef OBJ_ELF
--- 2638,2645 ----
arm_s_text (ignore)
int ignore;
{
! if (now_seg != text_section
! && dump_lit_pool_on_section_change)
s_ltorg (0);
#ifdef OBJ_ELF
*************** static void
*** 2570,2575 ****
--- 2653,2660 ----
arm_s_data (ignore)
int ignore;
{
+ if (dump_lit_pool_on_section_change)
+ {
if (flag_readonly_data_in_text)
{
if (now_seg != text_section)
*************** arm_s_data (ignore)
*** 2577,2582 ****
--- 2662,2668 ----
}
else if (now_seg != data_section)
s_ltorg (0);
+ }
#ifdef OBJ_ELF
obj_elf_data (ignore);
*************** static void
*** 2589,2594 ****
--- 2675,2681 ----
arm_s_section (ignore)
int ignore;
{
+ if (dump_lit_pool_on_section_change)
s_ltorg (0);
#ifdef OBJ_ELF
*************** tc_gen_reloc (section, fixp)
*** 10254,10263 ****
case BFD_RELOC_ARM_LITERAL:
case BFD_RELOC_ARM_HWLITERAL:
! /* If this is called then the a literal has been referenced across
! a section boundary - possibly due to an implicit dump. */
as_bad_where (fixp->fx_file, fixp->fx_line,
_("literal referenced across section boundary (Implicit dump?)"));
return NULL;
#ifdef OBJ_ELF
--- 10341,10356 ----
case BFD_RELOC_ARM_LITERAL:
case BFD_RELOC_ARM_HWLITERAL:
! /* If this is called then the a literal has
! been referenced across a section boundary. */
! if (dump_lit_pool_on_section_change)
! /* This might have ahppened because the literal was
! dumped into a pool when a section change occured. */
as_bad_where (fixp->fx_file, fixp->fx_line,
_("literal referenced across section boundary (Implicit dump?)"));
+ else
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("Literal referenced across section boundary"));
return NULL;
#ifdef OBJ_ELF
*************** md_assemble (str)
*** 10504,10511 ****
-k Generate PIC code
-mthumb Start in Thumb mode
-mthumb-interwork Code supports ARM/Thumb interworking
! For now we will also provide support for
-mapcs-32 32-bit Program counter
-mapcs-26 26-bit Program counter
--- 10597,10605 ----
-k Generate PIC code
-mthumb Start in Thumb mode
-mthumb-interwork Code supports ARM/Thumb interworking
+ -mimplicit-litpool-dump Dump literal pool on section change
! For now we will also provide support for:
-mapcs-32 32-bit Program counter
-mapcs-26 26-bit Program counter
*************** struct arm_option_table arm_opts[] =
*** 10598,10603 ****
--- 10692,10704 ----
{"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 1,
NULL},
+ {"mimplicit-litpool-dump",
+ N_("Automatically dump the literal pool on section change"),
+ & dump_lit_pool_on_section_change, 1, NULL},
+ {"mno-implicit-litpool-dump",
+ N_("Automatically dump the literal pool on section change"),
+ & dump_lit_pool_on_section_change, 0, NULL},
+
/* These are recognized by the assembler, but have no affect on code. */
{"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
{"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
*************** cons_fix_new_arm (frag, where, size, exp
*** 11210,11221 ****
void
arm_cleanup ()
{
! if (current_poolP == NULL)
! return;
! /* Put it at the end of text section. */
! subseg_set (text_section, 0);
s_ltorg (0);
}
void
--- 11311,11324 ----
void
arm_cleanup ()
{
! literal_pool * pool;
! for (pool = list_of_pools; pool; pool = pool->next)
! {
! /* Put it at the end of the relevent section. */
! subseg_set (pool->section, pool->sub_section);
s_ltorg (0);
+ }
}
void
Index: gas/doc/c-arm.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-arm.texi,v
retrieving revision 1.15
diff -c -3 -p -w -r1.15 c-arm.texi
*** gas/doc/c-arm.texi 21 Jan 2002 00:20:58 -0000 1.15
--- gas/doc/c-arm.texi 26 Jul 2002 15:20:48 -0000
*************** conventions, based on a beta release rel
*** 228,233 ****
--- 228,248 ----
specifications, rather than the default conventions which are based on
the final release of the ARM-ELF specifications.
+ @cindex @code{-mimplicit-litpool-dump} command line option, ARM
+ @item -mimplicit-pool-dump
+ This indicates that the current literal pool should be dumped
+ whenever a section change occurs. This was the default behavior of
+ earlier versions of the assembler.
+
+ @cindex @code{-mno-implicit-litpool-dump} command line option, ARM
+ @item -mno-implicit-pool-dump
+ This restores the default behavior of the assembler. Literal pools
+ will be accumulated on a per section and per sub-section basis and
+ only dumped when a @code{.ltorg} directive is encountered in the
+ relevant section/sub-section. If there are any non-empty literal
+ pools at the of assembly they will be dumped at the end of their
+ relevant sections/sub-sections.
+
@end table
Index: gas/doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.69
diff -c -3 -p -w -r1.69 as.texinfo
*** gas/doc/as.texinfo 22 Jul 2002 19:04:28 -0000 1.69
--- gas/doc/as.texinfo 26 Jul 2002 15:20:50 -0000
*************** gcc(1), ld(1), and the Info entries for
*** 296,301 ****
--- 296,302 ----
[@b{-mapcs-32}|@b{-mapcs-26}|@b{-mapcs-float}|
@b{-mapcs-reentrant}]
[@b{-mthumb-interwork}] [@b{-moabi}] [@b{-k}]
+ [@b{-mimplicit-litpool-dump}|@b{-mno-implicit-litpool-dump}]
@end ifset
@ifset CRIS
*************** Specify that the code has been generated
*** 621,626 ****
--- 622,629 ----
ARM code in mind.
@item -k
Specify that PIC code has been generated.
+ @item -mimplicit-litpool-dump
+ Cause the literal pool to be dumped every time a section change occurs.
@end table
@end ifset