Added __attribute__((alias)) support
authorRobert Pengelly <robertapengelly@hotmail.com>
Sun, 23 Aug 2026 02:20:17 +0000 (03:20 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Sun, 23 Aug 2026 02:20:17 +0000 (03:20 +0100)
amd64.c
i386.c
parse.c
parse.h

diff --git a/amd64.c b/amd64.c
index fa4abdc89fb14a15ee1d0327de3942454b28cfe7..c7a04bfc7f01f10d51cb0269b5392063f9859d6f 100644 (file)
--- a/amd64.c
+++ b/amd64.c
@@ -39686,6 +39686,22 @@ static void parse_external_after_type (void) {
         
         }
         
+        if (declarator_alias_target[0]) {
+        
+            if (!name) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "'alias' attribute requires a named declaration");
+            } else if (!declarator_has_function || declarator_function_is_pointer) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "'alias' attribute is only supported for functions");
+            } else if (tok.kind == TOK_LBRACE || is_type_start (tok.kind)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "function '%s' cannot be both defined and declared with 'alias'", name);
+            } else {
+                record_dllalias (name, declarator_alias_target, declaration_dllexport || parsed_dllexport || declarator_dllexport);
+            }
+            
+            declarator_alias_target[0] = '\0';
+        
+        }
+        
         if (name && declarator_has_function && (tok.kind == TOK_LBRACE || is_type_start (tok.kind))) {
         
             if (declaration_dllexport || parsed_dllexport || declarator_dllexport) {
@@ -39924,6 +39940,26 @@ static void parse_external_after_type (void) {
 
 }
 
+static int dll_export_name_is_present (const char *wanted) {
+
+    long i;
+    
+    if (!wanted) {
+        return 0;
+    }
+    
+    for (i = 0; i < vec_dllexports.length; i++) {
+    
+        if (vec_dllexports.data[i] && strcmp (vec_dllexports.data[i], wanted) == 0) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
 void compile_translation_unit64 (void) {
 
     if (state->ofp) {
@@ -39976,7 +40012,7 @@ void compile_translation_unit64 (void) {
     
     emit_pending_extern_symbols ();
     
-    if (vec_dllexports.length) {
+    if (vec_dllexports.length || vec_dllaliases.length) {
     
         char *p, *tmp;
         
@@ -40009,6 +40045,26 @@ void compile_translation_unit64 (void) {
             
             }
             
+            for (i = 0; i < vec_dllaliases.length; i++) {
+            
+                struct dll_alias_entry *entry = vec_dllaliases.data[i];
+                
+                const char *alias_name;
+                const char *target_name;
+                
+                if (!entry || !entry->dllexport || !dll_export_name_is_present (entry->target)) {
+                    continue;
+                }
+                
+                alias_name = asm_global_symbol_name (entry->name);
+                target_name = asm_global_symbol_name (entry->target);
+                
+                if (alias_name && target_name) {
+                    fprintf (fp, "    %s=%s\n", alias_name, target_name);
+                }
+            
+            }
+            
             fclose (fp);
             
         }
diff --git a/i386.c b/i386.c
index b7a9a825ae427dd23415446e116f41d1dc493fb3..15d7553aa107f5cd8eece30f407dcaec6792b621 100644 (file)
--- a/i386.c
+++ b/i386.c
@@ -36929,6 +36929,7 @@ static void parse_external_after_type (void) {
         
         int declaration_noreturn = 0;
         int declaration_dllimport = 0;
+        int declaration_dllexport = 0;
         
         int decl_is_pointer;
         int decl_pointer_depth;
@@ -36953,11 +36954,13 @@ static void parse_external_after_type (void) {
         declaration_is_inline = parsed_type_is_inline;
         declaration_storage = parsed_storage_class;
         declaration_dllimport = parsed_dllimport;
+        declaration_dllexport = parsed_dllexport;
         declaration_noreturn = parsed_noreturn;
         
         parse_declarator (&name);
         
         declaration_dllimport = declaration_dllimport || parsed_dllimport || declarator_dllimport;
+        declaration_dllexport = declaration_dllexport || parsed_dllexport || declarator_dllexport;
         declaration_noreturn = declaration_noreturn || parsed_noreturn || declarator_noreturn;
         
         apply_typedef_array_to_declarator ();
@@ -37016,13 +37019,31 @@ static void parse_external_after_type (void) {
         
         }
         
+        if (declarator_alias_target[0]) {
+        
+            if (!name) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "'alias' attribute requires a named declaration");
+            } else if (!declarator_has_function || declarator_function_is_pointer) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "'alias' attribute is only supported for functions");
+            } else if (tok.kind == TOK_LBRACE || is_type_start (tok.kind)) {
+                report_line_at (get_filename (), name_line, REPORT_ERROR, name_start, name_caret, "function '%s' cannot be both defined and declared with 'alias'", name);
+            } else {
+                record_dllalias (name, declarator_alias_target, declaration_dllexport || parsed_dllexport || declarator_dllexport);
+            }
+            
+            declarator_alias_target[0] = '\0';
+        
+        }
+        
         if (name && declarator_has_function && (tok.kind == TOK_LBRACE || is_type_start (tok.kind))) {
         
-            if (parsed_dllexport || declarator_dllexport) {
+            if (declaration_dllexport || parsed_dllexport || declarator_dllexport) {
             
                 vec_push (&vec_dllexports, xstrdup (name));
                 
                 declarator_dllexport = 0;
+                declaration_dllexport = 0;
+                
                 parsed_dllexport = 0;
             
             }
@@ -37252,6 +37273,26 @@ static void parse_external_after_type (void) {
 
 }
 
+static int dll_export_name_is_present (const char *wanted) {
+
+    long i;
+    
+    if (!wanted) {
+        return 0;
+    }
+    
+    for (i = 0; i < vec_dllexports.length; i++) {
+    
+        if (vec_dllexports.data[i] && strcmp (vec_dllexports.data[i], wanted) == 0) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
 void compile_translation_unit32 (void) {
 
     if (state->ofp) {
@@ -37307,7 +37348,7 @@ void compile_translation_unit32 (void) {
     
     emit_pending_extern_symbols ();
     
-    if (vec_dllexports.length) {
+    if (vec_dllexports.length || vec_dllaliases.length) {
     
         char *p, *tmp;
         
@@ -37340,6 +37381,26 @@ void compile_translation_unit32 (void) {
             
             }
             
+            for (i = 0; i < vec_dllaliases.length; i++) {
+            
+                struct dll_alias_entry *entry = vec_dllaliases.data[i];
+                
+                const char *alias_name;
+                const char *target_name;
+                
+                if (!entry || !entry->dllexport || !dll_export_name_is_present (entry->target)) {
+                    continue;
+                }
+                
+                alias_name = asm_global_symbol_name (entry->name);
+                target_name = asm_global_symbol_name (entry->target);
+                
+                if (alias_name && target_name) {
+                    fprintf (fp, "    %s=%s\n", alias_name, target_name);
+                }
+            
+            }
+            
             fclose (fp);
             
         }
diff --git a/parse.c b/parse.c
index 94a14c128b6cb6d17f1d28eaa763fd7a66dec360..3f30111ff9e6b5681c7a0c139696db71948a6b7a 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -23,6 +23,7 @@ enum token_kind postfix_member_calling_convention = TOK_EOF;
 enum token_kind parsed_calling_convention = TOK_EOF;
 
 struct vector vec_dllexports = { 0 };
+struct vector vec_dllaliases = { 0 };
 
 int parsed_dllexport = 0;
 int parsed_dllimport = 0;
@@ -68,6 +69,8 @@ int declarator_noreturn = 0;
 int declarator_dllexport = 0;
 int declarator_dllimport = 0;
 
+char declarator_alias_target[512] = { 0 };
+
 enum token_kind declarator_calling_convention = TOK_EOF;
 int global_initializer_accept_symbol_addresses = 0;
 
@@ -122,6 +125,24 @@ int is_string_token (void) {
     return tok.kind == TOK_PPSTR || tok.kind == TOK_LSTR;
 }
 
+void record_dllalias (const char *name, const char *target, int dllexport) {
+
+    struct dll_alias_entry *entry;
+    
+    if (!name || !*name || !target || !*target) {
+        return;
+    }
+    
+    entry = xmalloc (sizeof (*entry));
+    
+    entry->name = xstrdup (name);
+    entry->target = xstrdup (target);
+    
+    entry->dllexport = dllexport;
+    vec_push (&vec_dllaliases, entry);
+
+}
+
 int expect (enum token_kind k, const char *what) {
 
     if (tok.kind == k) {
@@ -443,6 +464,62 @@ static void skip_attribute_arguments (void) {
 
 }
 
+static int parse_alias_attribute_argument (void) {
+
+    const char *s;
+    size_t len;
+    
+    if (!_accept (TOK_LPAREN)) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.report_start, tok.report_caret, "expected '(' after 'alias'");
+        return 0;
+    
+    }
+    
+    if (!is_string_token () || !tok.ident || tok.kind == TOK_LSTR) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.report_start, tok.report_caret, "expected string literal in 'alias' attribute");
+        
+        skip_attribute_arguments ();
+        return 0;
+    
+    }
+    
+    s = tok.ident;
+    len = strlen (s);
+    
+    if (len < 2 || s[0] != '"' || s[len - 1] != '"') {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.report_start, tok.report_caret, "invalid string literal in 'alias' attribute");
+        
+        get_token ();
+        expect (TOK_RPAREN, ")");
+        
+        return 0;
+    
+    }
+    
+    if (len - 2 >= sizeof (declarator_alias_target)) {
+    
+        report_line_at (get_filename (), get_line_number (), REPORT_ERROR, tok.report_start, tok.report_caret, "alias target name is too long");
+        
+        get_token ();
+        expect (TOK_RPAREN, ")");
+        
+        return 0;
+    
+    }
+    
+    memcpy (declarator_alias_target, s + 1, len - 2);
+    declarator_alias_target[len - 2] = '\0';
+    
+    get_token ();
+    
+    expect (TOK_RPAREN, ")");
+    return 1;
+
+}
+
 static void apply_decl_attribute (const char *spelling, int is_gnu) {
 
     if (attribute_name_is (spelling, "dllexport")) {
@@ -555,12 +632,18 @@ static void parse_decl_modifier (void) {
             } else {
             
                 name = xstrdup (tok.ident);
-                
-                apply_decl_attribute (name, 1);
                 get_token ();
                 
-                if (tok.kind == TOK_LPAREN) {
-                    skip_attribute_arguments ();
+                if (attribute_name_is (name, "alias")) {
+                    parse_alias_attribute_argument ();
+                } else {
+                
+                    apply_decl_attribute (name, 1);
+                    
+                    if (tok.kind == TOK_LPAREN) {
+                        skip_attribute_arguments ();
+                    }                
+                
                 }
                 
                 free (name);
@@ -741,12 +824,14 @@ void parse_declarator (char **out_name) {
     const char *saved_captured_declarator_name_caret = captured_declarator_name_caret;
 
     enum token_kind saved_declarator_calling_convention = declarator_calling_convention;
+    char saved_declarator_alias_target[sizeof declarator_alias_target];
     
     int saved_declarator_dllexport = declarator_dllexport;
     int saved_declarator_dllimport = declarator_dllimport;
     int saved_declarator_noreturn = declarator_noreturn;
     
     unsigned long saved_captured_declarator_name_line = captured_declarator_name_line;
+    memcpy (saved_declarator_alias_target, declarator_alias_target, sizeof (declarator_alias_target));
     
     if (top_level) {
     
@@ -757,6 +842,8 @@ void parse_declarator (char **out_name) {
         declarator_calling_convention = TOK_EOF;
         capture_declarator_name_location = 1;
         
+        memcpy (declarator_alias_target, saved_declarator_alias_target, sizeof (declarator_alias_target));
+        
         declarator_dllexport = 0;
         declarator_dllimport = 0;
         declarator_noreturn = 0;
diff --git a/parse.h b/parse.h
index edef0cb4e769310b10975517b1905eb19a4ea5a6..75de67d97918176053dd3aa64426ec1e9aa03f16 100644 (file)
--- a/parse.h
+++ b/parse.h
@@ -18,6 +18,14 @@ extern enum token_kind last_found_member_calling_convention;
 extern enum token_kind postfix_member_calling_convention;
 extern enum token_kind parsed_calling_convention;
 
+struct dll_alias_entry {
+
+    char *target, *name;
+    int dllexport;
+
+};
+
+extern struct vector vec_dllaliases;
 extern struct vector vec_dllexports;
 
 extern int parsed_dllexport;
@@ -59,6 +67,7 @@ extern int declarator_is_pointer;
 extern int declarator_pointer_depth;
 extern int declarator_has_array;
 
+extern char declarator_alias_target[512];
 extern int declarator_dllexport;
 extern int declarator_dllimport;
 extern int declarator_noreturn;
@@ -102,6 +111,7 @@ int parse_constexpr_address_of_null_member (int64_s *out);
 int parse_cast_type_name (int *out_size, int *out_is_unsigned, int *out_is_pointer);
 
 int resolve_enum_constant (const char *name, int64_s *out);
+void record_dllalias (const char *name, const char *target, int dllexport);
 
 #define     DATA_CHAR                   (1 | (1 << 5))
 #define     DATA_SHORT                  (2 | (1 << 6))