csymbols

Why is memcpy listed in the symbols despite not being explicitly used in my function?


I noticed that compiling a file with a single simple function on a type involving nested unions somehow causes nm to list memcpy among the symbols as undefined ("U") despite memcpy not being used.

Why? Is there some implicit use of it due to the way my types are designed?

MRE:

#ifndef MRE_H
# define MRE_H

# include <stddef.h>

# define HISTORY_SIZE   1024

typedef                 enum e_call_ent_type {
    E_MALLOC_ENT = 0,
    E_FREE_ENT = 1,
    E_REALLOC_ENT = 2
}                       t_call_ent_type;

typedef                 struct s_call_ent {
    t_call_ent_type     type;
}                       t_call_ent;

typedef                 enum e_lock_ent_type {
    E_LOCKBASE_ENT = 0,
    E_UNLOCKBASE_ENT = 1
}                       t_lock_ent_type;

typedef                 struct s_lock_ent {
    t_lock_ent_type type;
}                       t_lock_ent;

typedef                 enum e_ent_type {
    E_VOID_ENT = 0,
    E_CALL_ENT = 1,
    E_LOCK_ENT = 2
}                       t_ent_type;

typedef                 struct s_ent
{
    t_ent_type          type;
    union u_ent         {
        t_call_ent      call_ent;
        t_lock_ent      lock_ent;
    }                   ent;
    int                 errno_val;
}                       t_ent;

typedef                 struct s_history {
    t_ent               entries[HISTORY_SIZE];
}                       t_history;


t_history               init_history(void);

#endif
#include "MRE.h"

t_history       init_history(void) {
    t_history   res;

    res.entries[0].type = E_VOID_ENT;
    return (res);
}

Compiling and running nm:

> gcc -Wall -Werror -Wextra -c -o init_history.o init_history.c
> nm init_history.o
0000000000000000 T init_history
                 U memcpy
                 U __stack_chk_fail

Update:


init_history.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <init_history>:
   0:   f3 0f 1e fa             endbr64 
   4:   55                      push   %rbp
   5:   48 89 e5                mov    %rsp,%rbp
   8:   48 81 ec 00 10 00 00    sub    $0x1000,%rsp
   f:   48 83 0c 24 00          orq    $0x0,(%rsp)
  14:   48 81 ec 00 10 00 00    sub    $0x1000,%rsp
  1b:   48 83 0c 24 00          orq    $0x0,(%rsp)
  20:   48 81 ec 00 10 00 00    sub    $0x1000,%rsp
  27:   48 83 0c 24 00          orq    $0x0,(%rsp)
  2c:   48 83 ec 20             sub    $0x20,%rsp
  30:   48 89 bd e8 cf ff ff    mov    %rdi,-0x3018(%rbp)
  37:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  3e:   00 00 
  40:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  44:   31 c0                   xor    %eax,%eax
  46:   c7 85 f0 cf ff ff 00    movl   $0x0,-0x3010(%rbp)
  4d:   00 00 00 
  50:   48 8b 85 e8 cf ff ff    mov    -0x3018(%rbp),%rax
  57:   48 89 c1                mov    %rax,%rcx
  5a:   48 8d 85 f0 cf ff ff    lea    -0x3010(%rbp),%rax
  61:   ba 00 30 00 00          mov    $0x3000,%edx
  66:   48 89 c6                mov    %rax,%rsi
  69:   48 89 cf                mov    %rcx,%rdi
  6c:   e8 00 00 00 00          call   71 <init_history+0x71>
  71:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  75:   64 48 2b 04 25 28 00    sub    %fs:0x28,%rax
  7c:   00 00 
  7e:   74 05                   je     85 <init_history+0x85>
  80:   e8 00 00 00 00          call   85 <init_history+0x85>
  85:   48 8b 85 e8 cf ff ff    mov    -0x3018(%rbp),%rax
  8c:   c9                      leave  
  8d:   c3                      ret    

Solution

  • If you look at the assembly instructions at offsets 6c and 80, you'll see a pair of CALL instructions with opcodes e8 00 00 00 00. Note that the destination offset i.e. the last 4 bytes are all 0. These are external functions calls that will get resolved at link time.

    If you link the object file into an executable and run objdump on the executable, you'll probably see that these instructions now point to memcpy.

    Since you're returning a struct by value, this call to memcpy is most likely doing this copy for the return value.