aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c73
1 files changed, 72 insertions, 1 deletions
diff --git a/builtin.c b/builtin.c
index 5c7321ca..c7e7da3b 100644
--- a/builtin.c
+++ b/builtin.c
@@ -454,6 +454,77 @@ static struct symbol_op atomic_op = {
};
+///
+// expand __builtin_object_size()
+//
+// :note: type 1 and type 3 are not supported because the
+// needed information isn't available after evaluation.
+static int expand_object_size(struct expression *expr, int cost)
+{
+ struct expression *arg = first_expression(expr->args);
+ int type = get_expression_value_silent(ptr_list_nth(expr->args, 1));
+ unsigned long val = -1, off = 0;
+
+ while (arg) {
+ switch (arg->type) {
+ case EXPR_IMPLIED_CAST:
+ case EXPR_CAST:
+ // ignore those
+ arg = arg->cast_expression;
+ continue;
+ case EXPR_BINOP:
+ // a constant add is (maybe) an offset
+ if (!arg->right || arg->op != '+' || arg->right->type != EXPR_VALUE)
+ break;
+ off += arg->right->value;
+ arg = arg->left;
+ continue;
+ case EXPR_PREOP:
+ // a deref is just intermediate variable
+ // and so the offset needs to be zeroed.
+ if (arg->op == '*') {
+ arg = arg->unop;
+ off = 0;
+ switch (arg->type) {
+ case EXPR_SYMBOL:
+ arg = arg->symbol->initializer;
+ continue;
+ default:
+ break;
+ }
+ }
+ break;
+ case EXPR_SYMBOL:
+ // the symbol we're looking after
+ val = bits_to_bytes(arg->symbol->bit_size);
+ break;
+ case EXPR_CALL:
+ // use alloc_size() attribute but only after linearization.
+ return UNSAFE;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (val == -1)
+ val = (type & 2) ? 0 : val;
+ else if (type & 1)
+ return UNSAFE;
+ else
+ val -= off;
+
+ expr->flags |= CEF_SET_ICE;
+ expr->type = EXPR_VALUE;
+ expr->value = val;
+ expr->taint = 0;
+ return 0;
+}
+
+static struct symbol_op object_size_op = {
+ .expand = expand_object_size,
+};
+
/*
* Builtin functions
*/
@@ -598,7 +669,7 @@ static const struct builtin_fn builtins_common[] = {
{ "__builtin_nan", &double_ctype, 0, { &const_string_ctype }},
{ "__builtin_nanf", &float_ctype, 0, { &const_string_ctype }},
{ "__builtin_nanl", &ldouble_ctype, 0, { &const_string_ctype }},
- { "__builtin_object_size", size_t_ctype, 0, { &const_ptr_ctype, &int_ctype }},
+ { "__builtin_object_size", size_t_ctype, 0, { &const_ptr_ctype, &int_ctype }, .op = &object_size_op},
{ "__builtin_parity", &int_ctype, 0, { &uint_ctype }, .op = &parity_op },
{ "__builtin_parityl", &int_ctype, 0, { &ulong_ctype }, .op = &parity_op },
{ "__builtin_parityll", &int_ctype, 0, { &ullong_ctype }, .op = &parity_op },