X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gas%2Ffrags.c;h=f5afe1a49b5e536b7702d719cc369d6ee91679bc;hb=292c7bf86de50ad643b929a7ac5769505d54e45f;hp=90096ff696d7b4809a487b3f4d73fc1a7d1fe6cb;hpb=db22231044df03bbcb987496f3f29f0462b2e9ee;p=binutils-gdb.git diff --git a/gas/frags.c b/gas/frags.c index 90096ff696d..f5afe1a49b5 100644 --- a/gas/frags.c +++ b/gas/frags.c @@ -1,5 +1,5 @@ /* frags.c - manage frags - - Copyright (C) 1987-2019 Free Software Foundation, Inc. + Copyright (C) 1987-2022 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -89,9 +89,9 @@ frag_alloc (struct obstack *ob) } /* Try to augment current frag by nchars chars. - If there is no room, close of the current frag with a ".fill 0" - and begin a new frag. Unless the new frag has nchars chars available - do not return. Do not set up any fields of *now_frag. */ + If there is no room, close off the current frag with a ".fill 0" + and begin a new frag. Then loop until the new frag has at least + nchars chars available. Does not set up any fields in frag_now. */ void frag_grow (size_t nchars) @@ -165,7 +165,9 @@ frag_new (size_t old_frags_var_max_size gas_assert (frchain_now->frch_last == frag_now); /* Fix up old frag's fr_fix. */ - frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size; + frag_now->fr_fix = frag_now_fix_octets (); + gas_assert (frag_now->fr_fix >= old_frags_var_max_size); + frag_now->fr_fix -= old_frags_var_max_size; /* Make sure its type is valid. */ gas_assert (frag_now->fr_type != 0); @@ -393,7 +395,12 @@ frag_now_fix_octets (void) addressT frag_now_fix (void) { - return frag_now_fix_octets () / OCTETS_PER_BYTE; + /* Symbols whose section has SEC_ELF_OCTETS set, + resolve to octets instead of target bytes. */ + if (now_seg->flags & SEC_OCTETS) + return frag_now_fix_octets (); + else + return frag_now_fix_octets () / OCTETS_PER_BYTE; } void @@ -412,7 +419,7 @@ frag_append_1_char (int datum) their start addresses. Set OFFSET to the difference in address not already accounted for in the frag FR_ADDRESS. */ -bfd_boolean +bool frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset) { const fragS *frag; @@ -424,7 +431,7 @@ frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset) if (frag1 == frag2) { *offset = off; - return TRUE; + return true; } /* Maybe frag2 is after frag1. */ @@ -438,7 +445,7 @@ frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset) if (frag == frag2) { *offset = off; - return TRUE; + return true; } } @@ -454,9 +461,106 @@ frag_offset_fixed_p (const fragS *frag1, const fragS *frag2, offsetT *offset) if (frag == frag1) { *offset = off; - return TRUE; + return true; + } + } + + return false; +} + +/* Return TRUE if FRAG2 follows FRAG1 with a fixed relationship + between the two assuming alignment frags do nothing. Set OFFSET to + the difference in address not already accounted for in the frag + FR_ADDRESS. */ + +bool +frag_offset_ignore_align_p (const fragS *frag1, const fragS *frag2, + offsetT *offset) +{ + const fragS *frag; + offsetT off; + + /* Start with offset initialised to difference between the two frags. + Prior to assigning frag addresses this will be zero. */ + off = frag1->fr_address - frag2->fr_address; + if (frag1 == frag2) + { + *offset = off; + return true; + } + + frag = frag1; + while (frag->fr_type == rs_fill + || frag->fr_type == rs_align + || frag->fr_type == rs_align_code + || frag->fr_type == rs_align_test) + { + if (frag->fr_type == rs_fill) + off += frag->fr_fix + frag->fr_offset * frag->fr_var; + frag = frag->fr_next; + if (frag == NULL) + break; + if (frag == frag2) + { + *offset = off; + return true; } } - return FALSE; + return false; +} + +/* Return TRUE if we can determine whether FRAG2 OFF2 appears after + (strict >, not >=) FRAG1 OFF1, assuming it is not before. Set + *OFFSET so that resolve_expression will resolve an O_gt operation + between them to false (0) if they are guaranteed to be at the same + location, or to true (-1) if they are guaranteed to be at different + locations. Return FALSE conservatively, e.g. if neither result can + be guaranteed (yet). + + They are known to be in the same segment, and not the same frag + (this is a fallback for frag_offset_fixed_p, that always takes care + of this case), and it is expected (from the uses this is designed + to simplify, namely location view increments) that frag2 is + reachable from frag1 following the fr_next links, rather than the + other way round. */ + +bool +frag_gtoffset_p (valueT off2, const fragS *frag2, + valueT off1, const fragS *frag1, offsetT *offset) +{ + /* Insanity check. */ + if (frag2 == frag1 || off1 > frag1->fr_fix) + return false; + + /* If the first symbol offset is at the end of the first frag and + the second symbol offset at the beginning of the second frag then + it is possible they are at the same address. Go looking for a + non-zero fr_fix in any frag between these frags. If found then + we can say the O_gt result will be true. If no such frag is + found we assume that frag1 or any of the following frags might + have a variable tail and thus the answer is unknown. This isn't + strictly true; some frags don't have a variable tail, but it + doesn't seem worth optimizing for those cases. */ + const fragS *frag = frag1; + offsetT delta = off2 - off1; + for (;;) + { + delta += frag->fr_fix; + frag = frag->fr_next; + if (frag == frag2) + { + if (delta == 0) + return false; + break; + } + /* If we run off the end of the frag chain then we have a case + where frag2 is not after frag1, ie. an O_gt expression not + created for .loc view. */ + if (frag == NULL) + return false; + } + + *offset = (off2 - off1 - delta) * OCTETS_PER_BYTE; + return true; }