aboutsummaryrefslogtreecommitdiff
path: root/gas/read.c
diff options
context:
space:
mode:
authorMark Harmstone <mark@harmstone.com>2024-11-02 22:05:06 +0000
committerMark Harmstone <mark@harmstone.com>2024-11-13 03:11:35 +0000
commitb3aa594daaec9ec736f721c3f77bd411b3e7c964 (patch)
tree39f35b7f92854b471f24ddcd8b20a157e11bba5e /gas/read.c
parent2e7d431af880736d6a6e8144a8e3d6d1e65008f5 (diff)
downloadbinutils-b3aa594daaec9ec736f721c3f77bd411b3e7c964.zip
binutils-b3aa594daaec9ec736f721c3f77bd411b3e7c964.tar.gz
binutils-b3aa594daaec9ec736f721c3f77bd411b3e7c964.tar.bz2
gas: add .cv_ucomp and .cv_scomp pseudo-directives
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))
Diffstat (limited to 'gas/read.c')
-rw-r--r--gas/read.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/gas/read.c b/gas/read.c
index aefbd7a..589c7b0 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -265,6 +265,9 @@ static void poend (void);
static size_t get_macro_line_sb (sb *);
static void generate_file_debug (void);
static char *_find_end_of_line (char *, int, int, int);
+#if defined (TE_PE) && defined (O_secrel)
+static void s_cv_comp (int sign);
+#endif
void
read_begin (void)
@@ -369,6 +372,10 @@ static const pseudo_typeS potable[] = {
{"comm", s_comm, 0},
{"common", s_mri_common, 0},
{"common.s", s_mri_common, 1},
+#if defined (TE_PE) && defined (O_secrel)
+ {"cv_scomp", s_cv_comp, 1},
+ {"cv_ucomp", s_cv_comp, 0},
+#endif
{"data", s_data, 0},
{"dc", cons, 2},
{"dc.a", cons, 0},
@@ -5457,6 +5464,97 @@ s_leb128 (int sign)
demand_empty_rest_of_line ();
}
+#if defined (TE_PE) && defined (O_secrel)
+
+/* Generate the appropriate fragments for a given expression to emit a
+ cv_comp value. SIGN is 1 for cv_scomp, 0 for cv_ucomp. */
+
+static void
+emit_cv_comp_expr (expressionS *exp, int sign)
+{
+ operatorT op = exp->X_op;
+
+ if (op == O_absent || op == O_illegal)
+ {
+ as_warn (_("zero assumed for missing expression"));
+ exp->X_add_number = 0;
+ op = O_constant;
+ }
+ else if (op == O_big)
+ {
+ as_bad (_("number invalid"));
+ exp->X_add_number = 0;
+ op = O_constant;
+ }
+ else if (op == O_register)
+ {
+ as_warn (_("register value used as expression"));
+ op = O_constant;
+ }
+
+ if (now_seg == absolute_section)
+ {
+ if (op != O_constant || exp->X_add_number != 0)
+ as_bad (_("attempt to store value in absolute section"));
+ abs_section_offset++;
+ return;
+ }
+
+ if ((op != O_constant || exp->X_add_number != 0) && in_bss ())
+ as_bad (_("attempt to store non-zero value in section `%s'"),
+ segment_name (now_seg));
+
+ /* Let the backend know that subsequent data may be byte aligned. */
+#ifdef md_cons_align
+ md_cons_align (1);
+#endif
+
+ if (op == O_constant)
+ {
+ offsetT value = exp->X_add_number;
+ unsigned int size;
+ char *p;
+
+ /* If we've got a constant, emit the thing directly right now. */
+
+ size = sizeof_cv_comp (value, sign);
+ p = frag_more (size);
+ if (output_cv_comp (p, value, sign) > size)
+ abort ();
+ }
+ else
+ {
+ /* Otherwise, we have to create a variable sized fragment and
+ resolve things later. */
+
+ frag_var (rs_cv_comp, 4, 0, sign, make_expr_symbol (exp), 0, NULL);
+ }
+}
+
+/* Parse the .cv_ucomp and .cv_scomp pseudos. */
+
+static void
+s_cv_comp (int sign)
+{
+ expressionS exp;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ do
+ {
+ expression (&exp);
+ emit_cv_comp_expr (&exp, sign);
+ }
+ while (*input_line_pointer++ == ',');
+
+ input_line_pointer--;
+ demand_empty_rest_of_line ();
+}
+
+#endif /* TE_PE && O_secrel */
+
/* Code for handling base64 encoded strings.
Based upon code in sharutils' lib/base64.c source file, written by
Simon Josefsson. Which was partially adapted from GNU MailUtils