cassemblyx86-64nasmld

Why am I getting `-bash: ./animalprogram.bin: No such file or directory` on a fully built and linked program?


OK so I'm trying to create some educational content, and I seem to have come to an impasse myself. I'm building a very simple C / ASM project just to demonstrate linkage. All appears fine and well until I actually go to run it. Here's what I've got:

Cat.C

extern void sayHello(char*);
extern void makeSound(int);


void CatStuff(){
    int type = 0;
    char name[] = "Cat";

    sayHello(& name[0]);
    makeSound(type);
}

Dog.C

extern void sayHello(char*);
extern void makeSound(int);


void DogStuff(){
    int type = 1;
    char name[] = "Dog";

    sayHello(& name[0]);
    makeSound(type);
}

Cow.C

extern void sayHello(char*);
extern void makeSound(int);


void CowStuff(){
    int type = 2;
    char name[] = "Cow";

    sayHello(& name[0]);
    makeSound(type);
}

Util.C

#include <stdio.h>

void sayHello(char* name){
    printf("%s\r\n", name);
}

AnimalSounds.asm

BITS 64

global _start
global makeSound
extern CatStuff
extern DogStuff
extern CowStuff

section .rodata
    snd_cat: db "Meow",0
    snd_dog: db "Woof",0
    snd_cow: db "Moo",0,0

section .text

    makeSound:
        cmp rdi, 0      ; if (0)
        je load_cat     ; goto load_cat();
        cmp rdi, 1      ; if (1)
        je load_dog     ; goto load_dog();
        cmp rdi, 2      ; if (2)
        je load_cow     ; goto load_cow();
    .end:
        ret


    load_cat:
        mov rdi, snd_cat
        call print
        jmp makeSound.end

    load_dog:
        mov rdi, snd_dog
        call print
        jmp makeSound.end

    load_cow:
        mov rdi, snd_cow
        call print
        jmp makeSound.end


    print:
        mov rax, 1   ; sys_write
        mov rsi, rdi ; char*
        mov rdi, 1   ; stdout
        mov rdx, 5   ; 5 characters
        syscall
        ret

    exit:
        mov rax, 60  ; sys_exit
        mov rdi, 0   ; exit code 0
        syscall
        

    _start:
        call CatStuff   ;
        call DogStuff   ;
        call CowStuff   ;
        call exit       ;

Build.sh

#! /bin/bash

# Compile C Source Files
gcc -c Cat.c  -o Cat.bin
gcc -c Dog.c  -o Dog.bin
gcc -c Cow.c  -o Cow.bin
gcc -c Util.c -o Util.bin

# Assemble the ASM Source File
nasm -felf64 -o AnimalSounds.bin AnimalSounds.asm

# Link them all together (along with LibC)

ld -lc ./Cat.bin ./Dog.bin ./Cow.bin ./Util.bin ./AnimalSounds.bin -o animalprogram.bin

It appears all fine and well. Builds with no output (no error).

Readelf looks good:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x4011c5
  Start of program headers:          64 (bytes into file)
  Start of section headers:          13856 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         19
  Section header string table index: 18

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000000f  0000000000000000   A       0     0     1
  [ 2] .hash             HASH             0000000000400248  00000248
       0000000000000018  0000000000000004   A       4     0     8
  [ 3] .gnu.hash         GNU_HASH         0000000000400260  00000260
       000000000000001c  0000000000000000   A       4     0     8
  [ 4] .dynsym           DYNSYM           0000000000400280  00000280
       0000000000000048  0000000000000018   A       5     1     8
  [ 5] .dynstr           STRTAB           00000000004002c8  000002c8
       0000000000000039  0000000000000000   A       0     0     1
  [ 6] .gnu.version      VERSYM           0000000000400302  00000302
       0000000000000006  0000000000000002   A       4     0     2
  [ 7] .gnu.version_r    VERNEED          0000000000400308  00000308
       0000000000000030  0000000000000000   A       5     1     8
  [ 8] .rela.plt         RELA             0000000000400338  00000338
       0000000000000030  0000000000000018  AI       4    14     8
  [ 9] .plt              PROGBITS         0000000000401000  00001000
       0000000000000030  0000000000000010  AX       0     0     16
  [10] .text             PROGBITS         0000000000401030  00001030
       00000000000001a9  0000000000000000  AX       0     0     16
  [11] .rodata           PROGBITS         0000000000402000  00002000
       0000000000000017  0000000000000000   A       0     0     4
  [12] .eh_frame         PROGBITS         0000000000402018  00002018
       00000000000000c0  0000000000000000   A       0     0     8
  [13] .dynamic          DYNAMIC          0000000000403eb0  00002eb0
       0000000000000150  0000000000000010  WA       5     0     8
  [14] .got.plt          PROGBITS         0000000000404000  00003000
       0000000000000028  0000000000000008  WA       0     0     8
  [15] .comment          PROGBITS         0000000000000000  00003028
       000000000000002b  0000000000000001  MS       0     0     1
  [16] .symtab           SYMTAB           0000000000000000  00003058
       0000000000000420  0000000000000018          17    33     8
  [17] .strtab           STRTAB           0000000000000000  00003478
       000000000000010c  0000000000000000           0     0     1
  [18] .shstrtab         STRTAB           0000000000000000  00003584
       0000000000000096  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R      0x8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000000f 0x000000000000000f  R      0x1
      [Requesting program interpreter: /lib/ld64.so.1]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000368 0x0000000000000368  R      0x1000
  LOAD           0x0000000000001000 0x0000000000401000 0x0000000000401000
                 0x00000000000001d9 0x00000000000001d9  R E    0x1000
  LOAD           0x0000000000002000 0x0000000000402000 0x0000000000402000
                 0x00000000000000d8 0x00000000000000d8  R      0x1000
  LOAD           0x0000000000002eb0 0x0000000000403eb0 0x0000000000403eb0
                 0x0000000000000178 0x0000000000000178  RW     0x1000
  DYNAMIC        0x0000000000002eb0 0x0000000000403eb0 0x0000000000403eb0
                 0x0000000000000150 0x0000000000000150  RW     0x8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RWE    0x10
  GNU_RELRO      0x0000000000002eb0 0x0000000000403eb0 0x0000000000403eb0
                 0x0000000000000150 0x0000000000000150  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.plt
   03     .plt .text
   04     .rodata .eh_frame
   05     .dynamic .got.plt
   06     .dynamic
   07
   08     .dynamic

Dynamic section at offset 0x2eb0 contains 16 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000004 (HASH)               0x400248
 0x000000006ffffef5 (GNU_HASH)           0x400260
 0x0000000000000005 (STRTAB)             0x4002c8
 0x0000000000000006 (SYMTAB)             0x400280
 0x000000000000000a (STRSZ)              57 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000015 (DEBUG)              0x0
 0x0000000000000003 (PLTGOT)             0x404000
 0x0000000000000002 (PLTRELSZ)           48 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x400338
 0x000000006ffffffe (VERNEED)            0x400308
 0x000000006fffffff (VERNEEDNUM)         1
 0x000000006ffffff0 (VERSYM)             0x400302
 0x0000000000000000 (NULL)               0x0

Relocation section '.rela.plt' at offset 0x338 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000404018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 __stack_chk_fail@GLIBC_2.4 + 0
000000404020  000200000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

Symbol table '.dynsym' contains 3 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@GLIBC_2.4 (2)
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.2.5 (3)

Symbol table '.symtab' contains 44 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000400238     0 SECTION LOCAL  DEFAULT    1
     2: 0000000000400248     0 SECTION LOCAL  DEFAULT    2
     3: 0000000000400260     0 SECTION LOCAL  DEFAULT    3
     4: 0000000000400280     0 SECTION LOCAL  DEFAULT    4
     5: 00000000004002c8     0 SECTION LOCAL  DEFAULT    5
     6: 0000000000400302     0 SECTION LOCAL  DEFAULT    6
     7: 0000000000400308     0 SECTION LOCAL  DEFAULT    7
     8: 0000000000400338     0 SECTION LOCAL  DEFAULT    8
     9: 0000000000401000     0 SECTION LOCAL  DEFAULT    9
    10: 0000000000401030     0 SECTION LOCAL  DEFAULT   10
    11: 0000000000402000     0 SECTION LOCAL  DEFAULT   11
    12: 0000000000402018     0 SECTION LOCAL  DEFAULT   12
    13: 0000000000403eb0     0 SECTION LOCAL  DEFAULT   13
    14: 0000000000404000     0 SECTION LOCAL  DEFAULT   14
    15: 0000000000000000     0 SECTION LOCAL  DEFAULT   15
    16: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Cat.c
    17: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Dog.c
    18: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Cow.c
    19: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Util.c
    20: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS AnimalSounds.asm
    21: 0000000000402008     0 NOTYPE  LOCAL  DEFAULT   11 snd_cat
    22: 000000000040200d     0 NOTYPE  LOCAL  DEFAULT   11 snd_dog
    23: 0000000000402012     0 NOTYPE  LOCAL  DEFAULT   11 snd_cow
    24: 0000000000401172     0 NOTYPE  LOCAL  DEFAULT   10 makeSound.end
    25: 0000000000401173     0 NOTYPE  LOCAL  DEFAULT   10 load_cat
    26: 0000000000401184     0 NOTYPE  LOCAL  DEFAULT   10 load_dog
    27: 0000000000401195     0 NOTYPE  LOCAL  DEFAULT   10 load_cow
    28: 00000000004011a6     0 NOTYPE  LOCAL  DEFAULT   10 print
    29: 00000000004011bb     0 NOTYPE  LOCAL  DEFAULT   10 exit
    30: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
    31: 0000000000403eb0     0 OBJECT  LOCAL  DEFAULT   13 _DYNAMIC
    32: 0000000000404000     0 OBJECT  LOCAL  DEFAULT   14 _GLOBAL_OFFSET_TABLE_
    33: 0000000000401132    43 FUNC    GLOBAL DEFAULT   10 sayHello
    34: 0000000000404028     0 NOTYPE  GLOBAL DEFAULT   14 _edata
    35: 0000000000401160     0 NOTYPE  GLOBAL DEFAULT   10 makeSound
    36: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __stack_chk_fail@@GLIBC_2
    37: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND printf@@GLIBC_2.2.5
    38: 0000000000401030    86 FUNC    GLOBAL DEFAULT   10 CatStuff
    39: 00000000004010dc    86 FUNC    GLOBAL DEFAULT   10 CowStuff
    40: 0000000000404028     0 NOTYPE  GLOBAL DEFAULT   14 _end
    41: 00000000004011c5     0 NOTYPE  GLOBAL DEFAULT   10 _start
    42: 0000000000404028     0 NOTYPE  GLOBAL DEFAULT   14 __bss_start
    43: 0000000000401086    86 FUNC    GLOBAL DEFAULT   10 DogStuff

Histogram for bucket list length (total of 1 bucket):
 Length  Number     % of total  Coverage
      0  0          (  0.0%)
      1  0          (  0.0%)      0.0%
      2  1          (100.0%)    100.0%

Version symbols section '.gnu.version' contains 3 entries:
 Addr: 0x0000000000400302  Offset: 0x000302  Link: 4 (.dynsym)
  000:   0 (*local*)       2 (GLIBC_2.4)     3 (GLIBC_2.2.5)

Version needs section '.gnu.version_r' contains 1 entry:
 Addr: 0x0000000000400308  Offset: 0x000308  Link: 5 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 2
  0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3
  0x0020:   Name: GLIBC_2.4  Flags: none  Version: 2

But when I run it:

-bash: ./animalprogram.bin: No such file or directory

Am I making some kind of stupid novice mistake? What am I forgetting? Why does this not work?


Solution

  • Nevermind I found https://www.reddit.com/r/asm/comments/opbsm0/no_such_file_or_directory_when_trying_to_run_a/

    The answer was the dynamic linker didn't exist. Ld was using the wrong path for some reason. Fixed it and it works now.

    ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 -lc ./Cat.bin ./Dog.bin ./Cow.bin ./Util.bin ./AnimalSounds.bin -o animalprogram.bin

    is what finally worked