Print this page
10366 ld(1) should support GNU-style linker sets
10581 ld(1) should know kernel modules are a thing

@@ -690,13 +690,14 @@
                          */
                         if (usdp->sd_flags & FLG_SY_MAPREF)
                                 usdp->sd_flags |= FLG_SY_MAPUSED;
 
                         DBG_CALL(Dbg_syms_updated(ofl, usdp, uname));
-                } else
+                } else {
                         ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_SYM_RESERVE),
                             uname, usdp->sd_file->ifl_name);
+                }
         } else {
                 /*
                  * If the symbol does not exist create it.
                  */
                 if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)

@@ -883,24 +884,118 @@
         ld_eprintf(ofl, ERR_NONE, MSG_INTL(format[type]),
             demangle(sdp->sd_name), name1, name2, name3);
 }
 
 /*
+ * If an undef symbol exists naming a bound for the output section,
+ * turn it into a defined symbol with the correct value.
+ *
+ * We set an arbitrary 1KB limit on the resulting symbol names.
+ */
+static void
+sym_add_bounds(Ofl_desc *ofl, Os_desc *osp, Word bound)
+{
+        Sym_desc *bsdp;
+        char symn[1024];
+        size_t nsz;
+
+        switch (bound) {
+        case SDAUX_ID_SECBOUND_START:
+                nsz = snprintf(symn, sizeof (symn), "%s%s",
+                    MSG_ORIG(MSG_SYM_SECBOUND_START), osp->os_name);
+                if (nsz >= sizeof (symn))
+                        return;
+                break;
+        case SDAUX_ID_SECBOUND_STOP:
+                nsz = snprintf(symn, sizeof (symn), "%s%s",
+                    MSG_ORIG(MSG_SYM_SECBOUND_STOP), osp->os_name);
+                if (nsz >= sizeof (symn))
+                        return;
+                break;
+        default:
+                assert(0);
+        }
+
+        if ((bsdp = ld_sym_find(symn, SYM_NOHASH, NULL, ofl)) != NULL) {
+                if ((bsdp->sd_shndx != SHN_UNDEF) &&
+                    (bsdp->sd_ref == REF_REL_NEED)) {
+                        ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_SYM_RESERVE),
+                            symn, bsdp->sd_file->ifl_name);
+                        return;
+                }
+
+                DBG_CALL(Dbg_syms_updated(ofl, bsdp, symn));
+
+                bsdp->sd_aux->sa_symspec = bound;
+                bsdp->sd_aux->sa_boundsec = osp;
+                bsdp->sd_flags |= FLG_SY_SPECSEC;
+                bsdp->sd_ref = REF_REL_NEED;
+                bsdp->sd_sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
+                bsdp->sd_sym->st_other = STV_PROTECTED;
+                bsdp->sd_isc = NULL;
+                bsdp->sd_sym->st_size = 0;
+                bsdp->sd_sym->st_value = 0;
+                bsdp->sd_shndx = bsdp->sd_sym->st_shndx = SHN_ABS;
+        }
+}
+
+static Boolean
+is_cname(const char *name)
+{
+        if (strlen(name) == strspn(name,
+            "abcdefghijklmnopqrstuvwxyz"
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+            "0123456789"
+            "_"))
+                return (TRUE);
+        else
+                return (FALSE);
+}
+
+/*
  * At this point all symbol input processing has been completed, therefore
  * complete the symbol table entries by generating any necessary internal
  * symbols.
  */
 uintptr_t
 ld_sym_spec(Ofl_desc *ofl)
 {
         Sym_desc        *sdp;
+        Sg_desc         *sgp;
+
+        DBG_CALL(Dbg_syms_spec_title(ofl->ofl_lml));
+
+        /*
+         * For each section in the output file, look for symbols named for the
+         * __start/__stop patterns.  If references exist, flesh the symbols to
+         * be defined.
+         *
+         * The symbols are given values at the same time as the other special
+         * symbols.
+         */
+        if (!(ofl->ofl_flags & FLG_OF_RELOBJ) ||
+            (ofl->ofl_flags & FLG_OF_KMOD)) {
+                Aliste          idx1;
+
+                for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
+                        Os_desc *osp;
+                        Aliste idx2;
+
+                        for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
+                                if (is_cname(osp->os_name)) {
+                                        sym_add_bounds(ofl, osp,
+                                            SDAUX_ID_SECBOUND_START);
+                                        sym_add_bounds(ofl, osp,
+                                            SDAUX_ID_SECBOUND_STOP);
+                                }
+                        }
+                }
+        }
 
         if (ofl->ofl_flags & FLG_OF_RELOBJ)
                 return (1);
 
-        DBG_CALL(Dbg_syms_spec_title(ofl->ofl_lml));
-
         if (sym_add_spec(MSG_ORIG(MSG_SYM_ETEXT), MSG_ORIG(MSG_SYM_ETEXT_U),
             SDAUX_ID_ETEXT, 0, (FLG_SY_DEFAULT | FLG_SY_EXPDEF),
             ofl) == S_ERROR)
                 return (S_ERROR);
         if (sym_add_spec(MSG_ORIG(MSG_SYM_EDATA), MSG_ORIG(MSG_SYM_EDATA_U),