nuttx/libs/libc/elf/elf_unload.c
Marco Casaroli ec78241ebe libs/libc/elf: Load an FDPIC object's data into the data heap.
An architecture that sets CONFIG_ARCH_USE_DATA_HEAP gives a loaded module
its data from up_dataheap_memalign(), because the ordinary heap is not where
that data belongs there.  The ELF loader honours it for every object but an
FDPIC one: an FDPIC object places its writable segment on its own, and that
allocation, and the two places that free it, still use lib_memalign() and
lib_free().  Its text already comes from the text heap.

So an FDPIC module's data goes to the data heap too, and back to it when the
module is unloaded or removed.

On mps3-an547, which sets both heaps, fdpicxip loaded the data of its two
instances at 0x1007220 and 0x104e480, in the ordinary heap.  With this change
they are at 0x21000000 and 0x21000180, in the SRAM2 data heap, and both
instances run.  In a protected build the difference matters: there the
ordinary heap is kernel memory, and the module takes a data access violation
on its first access to its data.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-09-30 13:39:45 -03:00

176 lines
4.9 KiB
C

/****************************************************************************
* libs/libc/elf/elf_unload.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include <nuttx/debug.h>
#include <nuttx/arch.h>
#include <nuttx/lib/elf.h>
#include "libc.h"
#include "elf/elf.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: libelf_unload
*
* Description:
* This function unloads the object from memory. This essentially undoes
* the actions of libelf_load(). It is called only under certain error
* conditions after the module has been loaded but not yet started.
*
* Returned Value:
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int libelf_unload(FAR struct mod_loadinfo_s *loadinfo)
{
/* Free all working buffers */
libelf_freebuffers(loadinfo);
#ifdef HAVE_LIBC_ELF_PIN
/* Give the pin back if the loader took one, so the filesystem can
* reclaim the extent.
*/
if (loadinfo->pinfile != NULL)
{
libelf_pinrelease(&loadinfo->pinfile);
}
#endif
#ifdef CONFIG_ARCH_ADDRENV
if (loadinfo->addrenv != NULL)
{
libelf_addrenv_free(loadinfo);
}
else
#endif
/* Release memory holding the relocated ELF image */
/* An FDPIC object placed its two segments separately. Free each one. If
* the text stayed on the media, it was never allocated, thus leave it.
*/
if (loadinfo->fdpic)
{
if (loadinfo->textalloc != 0 && loadinfo->xipbase == 0)
{
#ifdef CONFIG_ARCH_USE_TEXT_HEAP
up_textheap_free((FAR void *)loadinfo->textalloc);
#else
lib_free((FAR void *)loadinfo->textalloc);
#endif
}
if (loadinfo->datastart != 0)
{
#ifdef CONFIG_ARCH_USE_DATA_HEAP
up_dataheap_free((FAR void *)loadinfo->datastart);
#else
lib_free((FAR void *)loadinfo->datastart);
#endif
loadinfo->datastart = 0;
}
loadinfo->textalloc = 0;
loadinfo->textsize = 0;
loadinfo->datasize = 0;
}
/* Any other ET_DYN has a single allocation so we only free textalloc */
else if (loadinfo->ehdr.e_type != ET_DYN)
{
#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION
int i;
for (i = 0; loadinfo->sectalloc[i] != 0 &&
i < loadinfo->ehdr.e_shnum; i++)
{
# ifdef CONFIG_ARCH_USE_TEXT_HEAP
if (up_textheap_heapmember((FAR void *)loadinfo->sectalloc[i]))
{
up_textheap_free((FAR void *)loadinfo->sectalloc[i]);
}
else
# endif
# ifdef CONFIG_ARCH_USE_DATA_HEAP
if (up_dataheap_heapmember((FAR void *)loadinfo->sectalloc[i]))
{
up_dataheap_free((FAR void *)loadinfo->sectalloc[i]);
}
else
# endif
{
lib_free((FAR void *)loadinfo->sectalloc[i]);
}
}
lib_free(loadinfo->sectalloc);
#else
if (loadinfo->textalloc != 0 && loadinfo->xipbase == 0)
{
# if defined(CONFIG_ARCH_USE_TEXT_HEAP)
up_textheap_free((FAR void *)loadinfo->textalloc);
# else
lib_free((FAR void *)loadinfo->textalloc);
# endif
}
if (loadinfo->datastart != 0)
{
# if defined(CONFIG_ARCH_USE_DATA_HEAP)
up_dataheap_free((FAR void *)loadinfo->datastart);
# else
lib_free((FAR void *)loadinfo->datastart);
# endif
}
#endif
}
else
{
lib_free((FAR void *)loadinfo->textalloc);
}
/* Clear out all indications of the allocated address environment */
loadinfo->textalloc = 0;
loadinfo->datastart = 0;
loadinfo->textsize = 0;
loadinfo->datasize = 0;
return OK;
}