drivers/tty/serial/icom.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
When compiling the kernel with -ffunction-sections (e.g., for LTO,
livepatch, dead code elimination, AutoFDO, or Propeller), the startup()
function gets compiled into the .text.startup section. In some cases it
can even be cloned into .text.startup.constprop.0 or
.text.startup.isra.0.
However, the .text.startup and .text.startup.* section names are already
reserved for use by the compiler for __attribute__((constructor)) code.
This naming conflict causes the vmlinux linker script to wrongly place
startup() function code in .init.text, which gets freed during boot.
Fix that by renaming startup() to icom_startup(). For consistency, also
rename its shutdown() counterpart to icom_shutdown().
Fixes: 6568f14cb5ae ("vmlinux.lds: Exclude .text.startup and .text.exit from TEXT_MAIN")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202511151839.A810rWWM-lkp@intel.com/
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
For tip/objtool/core.
drivers/tty/serial/icom.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 7fb995a8490e..d00903cfa841 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -760,7 +760,7 @@ static void load_code(struct icom_port *icom_port)
dma_free_coherent(&dev->dev, 4096, new_page, temp_pci);
}
-static int startup(struct icom_port *icom_port)
+static int icom_startup(struct icom_port *icom_port)
{
unsigned long temp;
unsigned char cable_id, raw_cable_id;
@@ -832,7 +832,7 @@ static int startup(struct icom_port *icom_port)
return 0;
}
-static void shutdown(struct icom_port *icom_port)
+static void icom_shutdown(struct icom_port *icom_port)
{
unsigned long temp;
unsigned char cmdReg;
@@ -1311,7 +1311,7 @@ static int icom_open(struct uart_port *port)
int retval;
kref_get(&icom_port->adapter->kref);
- retval = startup(icom_port);
+ retval = icom_startup(icom_port);
if (retval) {
kref_put(&icom_port->adapter->kref, icom_kref_release);
@@ -1333,7 +1333,7 @@ static void icom_close(struct uart_port *port)
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
- shutdown(icom_port);
+ icom_shutdown(icom_port);
kref_put(&icom_port->adapter->kref, icom_kref_release);
}
--
2.51.1
On 19. 11. 25, 7:27, Josh Poimboeuf wrote: > When compiling the kernel with -ffunction-sections (e.g., for LTO, > livepatch, dead code elimination, AutoFDO, or Propeller), the startup() > function gets compiled into the .text.startup section. In some cases it > can even be cloned into .text.startup.constprop.0 or > .text.startup.isra.0. > > However, the .text.startup and .text.startup.* section names are already > reserved for use by the compiler for __attribute__((constructor)) code. > > This naming conflict causes the vmlinux linker script to wrongly place > startup() function code in .init.text, which gets freed during boot. This sounds rather error-prone. What are the patterns supposed to match actually? Can't *those* real victims™ be renamed to something less common instead? > Fix that by renaming startup() to icom_startup(). For consistency, also > rename its shutdown() counterpart to icom_shutdown(). I see also: drivers/staging/media/atomisp/i2c/atomisp-gc2235.c:static int startup(struct v4l2_subdev *sd) drivers/staging/media/atomisp/i2c/atomisp-ov2722.c:static int startup(struct v4l2_subdev *sd) drivers/tty/amiserial.c:static int startup(struct tty_struct *tty, struct serial_state *info) drivers/tty/synclink_gt.c:static int startup(struct slgt_info *info) thanks, -- js suse labs
On Wed, Nov 19, 2025 at 07:58:05AM +0100, Jiri Slaby wrote: > On 19. 11. 25, 7:27, Josh Poimboeuf wrote: > > When compiling the kernel with -ffunction-sections (e.g., for LTO, > > livepatch, dead code elimination, AutoFDO, or Propeller), the startup() > > function gets compiled into the .text.startup section. In some cases it > > can even be cloned into .text.startup.constprop.0 or > > .text.startup.isra.0. > > > > However, the .text.startup and .text.startup.* section names are already > > reserved for use by the compiler for __attribute__((constructor)) code. > > > > This naming conflict causes the vmlinux linker script to wrongly place > > startup() function code in .init.text, which gets freed during boot. > > This sounds rather error-prone. What are the patterns supposed to match > actually? Can't *those* real victims™ be renamed to something less common > instead? Yeah, this is a terrible mess. The problem is that when linking objects build with and without -ffunction-sections you can no longer uniquely identify what's what :-( As long as its consistently one or the other it works, but if you mix them constructors and normal function like this get mixed up. In another thread I've suggested this might be a toolchain bug, but even if they agree and fix it, we still stuck with the old compilers. And I'm not sure the toolchain people are agreeing there's anything wrong here -- the argument is that you shouldn't be mixing this or somesuch. Anyway, objtool has a warning for this, so new occurrences should be flagged before they get introduced. But yes, we need to make the tree clean first.
On Wed, Nov 19, 2025 at 09:43:15AM +0100, Peter Zijlstra wrote: > On Wed, Nov 19, 2025 at 07:58:05AM +0100, Jiri Slaby wrote: > > On 19. 11. 25, 7:27, Josh Poimboeuf wrote: > > > When compiling the kernel with -ffunction-sections (e.g., for LTO, > > > livepatch, dead code elimination, AutoFDO, or Propeller), the startup() > > > function gets compiled into the .text.startup section. In some cases it > > > can even be cloned into .text.startup.constprop.0 or > > > .text.startup.isra.0. > > > > > > However, the .text.startup and .text.startup.* section names are already > > > reserved for use by the compiler for __attribute__((constructor)) code. > > > > > > This naming conflict causes the vmlinux linker script to wrongly place > > > startup() function code in .init.text, which gets freed during boot. > > > > This sounds rather error-prone. What are the patterns supposed to match > > actually? Can't *those* real victims™ be renamed to something less common > > instead? > > Yeah, this is a terrible mess. The problem is that when linking objects > build with and without -ffunction-sections you can no longer uniquely > identify what's what :-( > > As long as its consistently one or the other it works, but if you mix > them constructors and normal function like this get mixed up. > > In another thread I've suggested this might be a toolchain bug, but even > if they agree and fix it, we still stuck with the old compilers. And I'm > not sure the toolchain people are agreeing there's anything wrong here > -- the argument is that you shouldn't be mixing this or somesuch. > > Anyway, objtool has a warning for this, so new occurrences should be > flagged before they get introduced. But yes, we need to make the tree > clean first. Also, that objtool warning only really works architectures that have objtool on, other archs can indeed silently create fail :-(
On Wed, Nov 19, 2025 at 09:44:35AM +0100, Peter Zijlstra wrote:
> On Wed, Nov 19, 2025 at 09:43:15AM +0100, Peter Zijlstra wrote:
> > On Wed, Nov 19, 2025 at 07:58:05AM +0100, Jiri Slaby wrote:
> > > On 19. 11. 25, 7:27, Josh Poimboeuf wrote:
> > > > When compiling the kernel with -ffunction-sections (e.g., for LTO,
> > > > livepatch, dead code elimination, AutoFDO, or Propeller), the startup()
> > > > function gets compiled into the .text.startup section. In some cases it
> > > > can even be cloned into .text.startup.constprop.0 or
> > > > .text.startup.isra.0.
> > > >
> > > > However, the .text.startup and .text.startup.* section names are already
> > > > reserved for use by the compiler for __attribute__((constructor)) code.
> > > >
> > > > This naming conflict causes the vmlinux linker script to wrongly place
> > > > startup() function code in .init.text, which gets freed during boot.
> > >
> > > This sounds rather error-prone. What are the patterns supposed to match
> > > actually? Can't *those* real victims™ be renamed to something less common
> > > instead?
> >
> > Yeah, this is a terrible mess. The problem is that when linking objects
> > build with and without -ffunction-sections you can no longer uniquely
> > identify what's what :-(
> >
> > As long as its consistently one or the other it works, but if you mix
> > them constructors and normal function like this get mixed up.
> >
> > In another thread I've suggested this might be a toolchain bug, but even
> > if they agree and fix it, we still stuck with the old compilers. And I'm
> > not sure the toolchain people are agreeing there's anything wrong here
> > -- the argument is that you shouldn't be mixing this or somesuch.
> >
> > Anyway, objtool has a warning for this, so new occurrences should be
> > flagged before they get introduced. But yes, we need to make the tree
> > clean first.
>
> Also, that objtool warning only really works architectures that have
> objtool on, other archs can indeed silently create fail :-(
Yeah, that is indeed unfortunate. Perhaps we should move this check out
of objtool and just make it some kind of script check like so?
nm vmlinux.o | awk '$2 ~ /^[TtWw]$/ {print $3}' | grep -E '^(startup|exit|split|unlikely|hot|unknown)(\.|$)'
I've got some more renames pending (see below), will post proper patches
in a bit.
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index 6fc39ab95e46..6050637a0def 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -491,7 +491,7 @@ static int gc2235_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
-static int startup(struct v4l2_subdev *sd)
+static int gc2235_startup(struct v4l2_subdev *sd)
{
struct gc2235_device *dev = to_gc2235_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -556,7 +556,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd,
return 0;
}
- ret = startup(sd);
+ ret = gc2235_startup(sd);
if (ret) {
dev_err(&client->dev, "gc2235 startup err\n");
goto err;
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 5af46442a792..81eaca751541 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -438,7 +438,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)
* ---------------------------------------------------------------
*/
-static int startup(struct tty_struct *tty, struct serial_state *info)
+static int rs_startup(struct tty_struct *tty, struct serial_state *info)
{
struct tty_port *port = &info->tport;
unsigned long flags;
@@ -513,7 +513,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct tty_struct *tty, struct serial_state *info)
+static void rs_shutdown(struct tty_struct *tty, struct serial_state *info)
{
unsigned long flags;
@@ -975,7 +975,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
change_speed(tty, state, NULL);
}
} else
- retval = startup(tty, state);
+ retval = rs_startup(tty, state);
tty_unlock(tty);
return retval;
}
@@ -1251,9 +1251,9 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
*/
rs_wait_until_sent(tty, state->timeout);
}
- shutdown(tty, state);
+ rs_shutdown(tty, state);
rs_flush_buffer(tty);
-
+
tty_ldisc_flush(tty);
port->tty = NULL;
@@ -1325,7 +1325,7 @@ static void rs_hangup(struct tty_struct *tty)
struct serial_state *info = tty->driver_data;
rs_flush_buffer(tty);
- shutdown(tty, info);
+ rs_shutdown(tty, info);
info->tport.count = 0;
tty_port_set_active(&info->tport, false);
info->tport.tty = NULL;
@@ -1349,7 +1349,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
port->tty = tty;
tty->driver_data = info;
- retval = startup(tty, info);
+ retval = rs_startup(tty, info);
if (retval) {
return retval;
}
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 3865b10d2d43..9d591fb291fd 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -407,9 +407,9 @@ static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value);
static void msc_set_vcr(struct slgt_info *info);
-static int startup(struct slgt_info *info);
+static int startup_hw(struct slgt_info *info);
static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info);
-static void shutdown(struct slgt_info *info);
+static void shutdown_hw(struct slgt_info *info);
static void program_hw(struct slgt_info *info);
static void change_params(struct slgt_info *info);
@@ -622,7 +622,7 @@ static int open(struct tty_struct *tty, struct file *filp)
if (info->port.count == 1) {
/* 1st open on this device, init hardware */
- retval = startup(info);
+ retval = startup_hw(info);
if (retval < 0) {
mutex_unlock(&info->port.mutex);
goto cleanup;
@@ -666,7 +666,7 @@ static void close(struct tty_struct *tty, struct file *filp)
flush_buffer(tty);
tty_ldisc_flush(tty);
- shutdown(info);
+ shutdown_hw(info);
mutex_unlock(&info->port.mutex);
tty_port_close_end(&info->port, tty);
@@ -687,7 +687,7 @@ static void hangup(struct tty_struct *tty)
flush_buffer(tty);
mutex_lock(&info->port.mutex);
- shutdown(info);
+ shutdown_hw(info);
spin_lock_irqsave(&info->port.lock, flags);
info->port.count = 0;
@@ -1445,7 +1445,7 @@ static int hdlcdev_open(struct net_device *dev)
spin_unlock_irqrestore(&info->netlock, flags);
/* claim resources and init adapter */
- if ((rc = startup(info)) != 0) {
+ if ((rc = startup_hw(info)) != 0) {
spin_lock_irqsave(&info->netlock, flags);
info->netcount=0;
spin_unlock_irqrestore(&info->netlock, flags);
@@ -1455,7 +1455,7 @@ static int hdlcdev_open(struct net_device *dev)
/* generic HDLC layer open processing */
rc = hdlc_open(dev);
if (rc) {
- shutdown(info);
+ shutdown_hw(info);
spin_lock_irqsave(&info->netlock, flags);
info->netcount = 0;
spin_unlock_irqrestore(&info->netlock, flags);
@@ -1499,7 +1499,7 @@ static int hdlcdev_close(struct net_device *dev)
netif_stop_queue(dev);
/* shutdown adapter and release resources */
- shutdown(info);
+ shutdown_hw(info);
hdlc_close(dev);
@@ -2328,7 +2328,7 @@ static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
return IRQ_HANDLED;
}
-static int startup(struct slgt_info *info)
+static int startup_hw(struct slgt_info *info)
{
DBGINFO(("%s startup\n", info->device_name));
@@ -2361,7 +2361,7 @@ static int startup(struct slgt_info *info)
/*
* called by close() and hangup() to shutdown hardware
*/
-static void shutdown(struct slgt_info *info)
+static void shutdown_hw(struct slgt_info *info)
{
unsigned long flags;
© 2016 - 2025 Red Hat, Inc.