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?
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