Link nasm with ld.lld linker - linker

I have main.s file.
extern printf
extern exit
section .data
fmt: db "hi!", 0xa
section .text
global _start
_start:
mov rax, 0
mov rdi, fmt
call printf
call exit
Compile and run
$ yasm -f elf64 main.s -o main.o
$ ld.lld main.o -o main --dynamic-linker /lib/ld-linux-x86-64.so.2
$ ./main
But i got:
ld.lld: error: undefined symbol: printf
ld.lld: error: undefined symbol: exit
ld.lld does not have -lc option like ld linker.

Just use : -L/lib option to tell the linker where to find libc
ld.lld main.o --dynamic-linker /lib/ld-linux-x86-64.so.2 -o main -L/lib -lc

Related

C makefile issue, undefined reference to function

Im trying to do a simple excercise in compilation.
I have 1 c file 1 assembly file and a makefile.
when I run the 'make' command I get the following error:
gcc -g -m32 -Wall -o mainAssignment0.o mainAssignment0.c
/tmp/ccXfVxtg.o: In function `main':
/home/caspl202/Desktop/tasks/Assignment0/mainAssignment0.c:12: undefined reference to `do_Str'
collect2: error: ld returned 1 exit status
makefile:10: recipe for target 'mainAssignment0.o' failed
make: * [mainAssignment0.o] Error 1
Meaning that for some reason the c program doesnt recognize the external ASM function.
Whats even weirder is that when I run the same makefile on the same files on a different machine it works like a charm. I would really like someone to shed some light on this thing.
C code:
#include <stdio.h>
#define MAX_LEN 100
extern int do_Str(char*);
int main(int argc, char** argv) {
char str_buf[MAX_LEN];
int counter = 0;
fgets(str_buf, MAX_LEN, stdin);
counter = do_Str (str_buf);
printf("%s%d\n",str_buf,counter);
return 0;
}
ASM code:
section .data
an: dd 0
section .text
global do_Str
do_Str:
push ebp
mov ebp, esp
pushad
mov ecx, dword [ebp+8]
loop:
cmp byte [ecx], 32
jnz noS
inc dword [an]
noS:
cmp byte [ecx], 65
jl noC
cmp byte [ecx], 90
jg noC
add byte [ecx], 32
noC:
inc ecx
cmp byte [ecx], 0
jnz loop
popad
mov eax,[an]
mov esp, ebp
pop ebp
ret
Makefile:
all: exec
libs: asm-lib
asm-lib: asmAssignment0.s
nasm -g -f elf -o asmAssignment0.o asmAssignment0.s
exec: mainAssignment0.c libs
gcc -g -m32 -c -o mainAssignment0.o mainAssignment0.c
gcc -g -m32 -o Assignment0.out mainAssignment0.o asmAssignment0.o
.PHONY: clean
clean:
rm -rf ./*.o Assignment0.out
You don't need to declare the function external.
int do_Str(char*);
Also, a function in C is prefixed with an underscore, so you must name it accordingly in your asm file.
global _do_Str
_do_Str:
The underscore is automatically added by the C compiler, so you don't have to use it in the C module.
The reason for your error you quote here is that your compile line is wrong. You can tell because you're trying to create an object file, but getting errors from the linker, so something is clearly not right:
gcc -g -m32 -Wall -o mainAssignment0.o mainAssignment0.c
...
collect2: error: ld returned 1 exit status
The problem is you forgot to add the -c flag to this compile line, so that the compiler generates an object file.
However, in your makefile the -c is present, so clearly this error you quote is not generated from the makefile you show us.
exec: mainAssignment0.c libs
gcc -g -m32 -c -o mainAssignment0.o mainAssignment0.c

Errors compiling sqrt function for RaspberryPI2 and BeableBoneBlack with arm-none-eabi-gcc compiler

i'm new in this type of coding and i'm trying to do some test executing bare-metal software for Cortex-A processors. I have experience with Cortex-M MCU and i compiled code with an IDE like ARM-Keil and with SDK by Nordic for some BLE jobs. Now i want to try to understand better the world of Cortex-A and i would learn coding in a bare-metal way, starting from some examples that i found online. I had some experiences with freeRTOS with Cortex-M, so i found online some git repository from some good guy that makes a porting of freeRTOS for RaspberryPI and BeableBoneBlack. From now on i will just explain my problem for the BeableBoneBlack, beacouse for the RaspberryPI it's similar.
I'm on linux, i installed gcc-arm-none-eabi compiler, so i cloned the BeagleBone Black with freeRTOS repository from this link.
I usually use VS Code to write code, so in the integrated terminal when i run the command make everything it's working and the of my BBB flashes correctly.
So now i would like to improve my code, and in order to do some tests i would like to use the rand() function, from stdlib.h. Unhappily I find that there are some errors: undefined reference to rand.
The last months, before doing tests with the BBB, i found other repos for RPi2 and i learn something about the linker of the arm-none-eabi compiler, that needs the addition of some parameters in order link library files during the process.
From this repo now i have two files: makedefs_ti and makefile. Opening the make file i found in line 26-27 the part of the generation of the file app, so where the linker is called. In this lines there are references to LIB_GCC and LIB_C, which are defined in the makedefs_ti. In lines 49-50 there are the references to the directory where the compiler is installed (I changed 4.7.3 with the correct one installed on my linux pc that is 9.2.1).
In the makefile, after -L$(LIB_C), if i add the linker parameters like -lc or -lg and try to recompile, i had error like arm-none-eabi-ld: cannot find -lc.
With some understanding from online resources i modified the the makedefs_ti as following:
# Toolchain/library path. LIB_PATH is an exported environmental variable which
# shall point to the installation of toolchain
#
#LIB_GCC=${LIB_PATH}/lib/gcc/arm-none-eabi/4.7.3/
#LIB_C=${LIB_PATH}/arm-none-eabi/lib/
LIB_GCC= /usr/lib/gcc/arm-none-eabi/9.2.1
LIB_C= /usr/lib/arm-none-eabi/lib
and the makefile :
$(LD) -o $#.out $< -T bbb.ld -Map bbb.map $(APP_LIB) $(LDFLAGS) $(RUNTIMELIB) -L $(LPATH) \
-L $(LIB_GCC) -lgcc -L $(LIB_C) -lc -lg
In this way my main.c file that calls a rand() function compile correctly.
During another test i tried to compile another code. Now i wrote a pair of .c and .h file (i placed them in the rtos directory in order to exploit the same makefile that is present there) that have inside a function that calls sqrt(). So, calling the function in the main() and compiling, even if i include everywhere <math.h> i have the error:
undefined reference to `sqrt'
and obviously the compilation stops.
Starting from this i tried to add another parameter to the linker, so i modified the makefile as following:
$(LD) -o $#.out $< -T bbb.ld -Map bbb.map $(APP_LIB) $(LDFLAGS) $(RUNTIMELIB) -L $(LPATH) \
-L $(LIB_GCC) -lgcc -L $(LIB_C) -lc -lg -lm
and i get other errors which i am unable to resolve in any way:
arm-none-eabi-ld: /usr/lib/arm-none-eabi/lib/libm.a(lib_a-w_sqrt.o): in function `sqrt':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:62: undefined reference to `__aeabi_dcmpun'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:63: undefined reference to `__aeabi_dcmplt'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:64: undefined reference to `__errno'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/math/../../../../../newlib/libm/math/w_sqrt.c:65: undefined reference to `__aeabi_ddiv'
arm-none-eabi-ld: /usr/lib/arm-none-eabi/lib/libm.a(lib_a-e_sqrt.o): in function `__ieee754_sqrt':
/build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:110: undefined reference to `__aeabi_dmul'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:110: undefined reference to `__aeabi_dadd'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:117: undefined reference to `__aeabi_dsub'
arm-none-eabi-ld: /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/newlib/libm/machine/arm/../../../../../../newlib/libm/machine/arm/../../math/e_sqrt.c:117: undefined reference to `__aeabi_ddiv'
make: *** [makefile:26: app] Errore 1
I would remark that, calling the sqrt() in the main works correctly, the problem happens when i call the sqrt() in other .c file. Instead the rand() function in the .c additional file works correctly.
I don't know how to resolve those errors, someone could help me?
What i tried another day is to write the same code in a Code Composer Studio project and it worked (with same functions that call sqrt and rand in additional .c file. What is the difference?
I'm very sorry if this is a long explanation, but i didn't find another way to explain my situation.
Thanks a lot in advance.
Salvo
start.s
.globl _start
_start:
;# enable fpu
mrc p15, 0, r0, c1, c0, 2
orr r0,r0,#0x300000 ;# single precision
orr r0,r0,#0xC00000 ;# double precision
mcr p15, 0, r0, c1, c0, 2
mov r0,#0x40000000
fmxr fpexc,r0
mov sp,#0x8000
bl notmain
hang: b hang
notmain.c
double notmain ( double a, double b )
{
return(a+b);
}
(not a real baremetal app, derived from one)
build for hard float
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mhard-float -mfpu=vfp -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
hardware float used
00008024 <notmain>:
8024: ee300b01 vadd.f64 d0, d0, d1
8028: e12fff1e bx lr
build for soft float
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-ld: notmain.o: in function `notmain':
notmain.c:(.text+0x4): undefined reference to `__aeabi_dadd'
Makefile:33: recipe for target 'notmain.elf' failed
make: *** [notmain.elf] Error 1
It needs gcclib.
Using gcc as a linker (I know how horrible a thought that is).
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf -lgcc
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
...
00008024 <notmain>:
8024: e92d4010 push {r4, lr}
8028: eb000003 bl 803c <__adddf3>
802c: e8bd8010 pop {r4, pc}
00008030 <__aeabi_drsub>:
8030: e2211102 eor r1, r1, #-2147483648 ; 0x80000000
8034: ea000000 b 803c <__adddf3>
00008038 <__aeabi_dsub>:
8038: e2233102 eor r3, r3, #-2147483648 ; 0x80000000
0000803c <__adddf3>:
803c: e92d4030 push {r4, r5, lr}
gcc is passing these to ld.
[0][/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/../../../../arm-none-eabi/bin/ld]
[1][-plugin]
[2][/opt/gnuarm/libexec/gcc/arm-none-eabi/10.2.0/liblto_plugin.so]
[3][-plugin-opt=/opt/gnuarm/libexec/gcc/arm-none-eabi/10.2.0/lto-wrapper]
[4][-plugin-opt=-fresolution=/tmp/ccRiWZtk.res]
[5][-X]
[6][-o]
[7][notmain.elf]
[8][-L/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0]
[9][-L/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/../../../../arm-none-eabi/lib]
[10][start.o]
[11][notmain.o]
[12][-lgcc]
[13][-T]
[14][memmap]
find | grep libgcc
./lib/gcc/arm-none-eabi/10.2.0/libgcc.a
./lib/gcc/arm-none-eabi/10.2.0/thumb/libgcc.a
./lib/gcc/arm-none-eabi/10.2.0/thumb/autofp/v7/fpu/libgcc.a
./lib/gcc/arm-none-eabi/10.2.0/arm/autofp/v5te/fpu/libgcc.a
So to use ld then
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf -L/opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/ -lgcc
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
Why does it use addf3 now? do not know.
00008024 <notmain>:
8024: e92d4010 push {r4, lr}
8028: eb000003 bl 803c <__adddf3>
802c: e8bd8010 pop {r4, pc}
00008030 <__aeabi_drsub>:
8030: e2211102 eor r1, r1, #-2147483648 ; 0x80000000
8034: ea000000 b 803c <__adddf3>
00008038 <__aeabi_dsub>:
8038: e2233102 eor r3, r3, #-2147483648 ; 0x80000000
0000803c <__adddf3>:
803c: e92d4030 push {r4, r5, lr}
8040: e1a04081 lsl r4, r1, #1
8044: e1a05083 lsl r5, r3, #1
That is how you deal with the aeabi stuff, you need to either use hard float or include the path to gcclib or just add it to the line
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /opt/gnuarm/lib/gcc/arm-none-eabi/10.2.0/libgcc.a
#arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf -lgcc
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
Now sqrt() is a C library thing not a gcc library thing so you need a C library (looks like you are trying to use newlib) and you need to build the C library to match gcc so you need to build it for hard or soft float and need to include the right library. Which I do not have...well....
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
so
double sqrt(double x);
double notmain ( double a )
{
return(sqrt(a));
}
looks familiar
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/libm.a
arm-none-eabi-ld: /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/libm.a(lib_a-w_sqrt.o): in function `sqrt':
w_sqrt.c:(.text.sqrt+0x34): undefined reference to `__aeabi_dcmpun'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0x6c): undefined reference to `__aeabi_dcmplt'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0xc4): undefined reference to `__aeabi_ddiv'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0xd8): undefined reference to `__errno'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0x120): undefined reference to `__errno'
arm-none-eabi-ld: /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/libm.a(lib_a-e_sqrt.o): in function `__ieee754_sqrt':
e_sqrt.c:(.text.__ieee754_sqrt+0x200): undefined reference to `__aeabi_dmul'
arm-none-eabi-ld: e_sqrt.c:(.text.__ieee754_sqrt+0x20c): undefined reference to `__aeabi_dadd'
arm-none-eabi-ld: e_sqrt.c:(.text.__ieee754_sqrt+0x22c): undefined reference to `__aeabi_dsub'
arm-none-eabi-ld: e_sqrt.c:(.text.__ieee754_sqrt+0x238): undefined reference to `__aeabi_ddiv'
Makefile:33: recipe for target 'notmain.elf' failed
make: *** [notmain.elf] Error 1
find
./arm-none-eabi/lib/libm.a
./arm-none-eabi/lib/thumb/v7e-m/nofp/libm.a
./arm-none-eabi/lib/thumb/v6-m/nofp/libm.a
./arm-none-eabi/lib/thumb/v8-m.base/nofp/libm.a
./arm-none-eabi/lib/thumb/v7/nofp/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+dp/hard/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+dp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7e-m+dp/hard/libm.a
./arm-none-eabi/lib/thumb/v7e-m+dp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7-r+fp.sp/hard/libm.a
./arm-none-eabi/lib/thumb/v7-r+fp.sp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7e-m+fp/hard/libm.a
./arm-none-eabi/lib/thumb/v7e-m+fp/softfp/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+fp/hard/libm.a
./arm-none-eabi/lib/thumb/v8-m.main+fp/softfp/libm.a
./arm-none-eabi/lib/thumb/v7-m/nofp/libm.a
./arm-none-eabi/lib/thumb/nofp/libm.a
./arm-none-eabi/lib/thumb/v7+fp/hard/libm.a
./arm-none-eabi/lib/thumb/v7+fp/softfp/libm.a
./arm-none-eabi/lib/thumb/v8-m.main/nofp/libm.a
./arm-none-eabi/lib/arm/v5te/hard/libm.a
./arm-none-eabi/lib/arm/v5te/softfp/libm.a
armv5te should work for armv6
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/softfp/libm.a
arm-none-eabi-ld: /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/softfp/libm.a(lib_a-w_sqrt.o): in function `sqrt':
w_sqrt.c:(.text.sqrt+0x94): undefined reference to `__errno'
arm-none-eabi-ld: w_sqrt.c:(.text.sqrt+0xdc): undefined reference to `__errno'
Makefile:33: recipe for target 'notmain.elf' failed
make: *** [notmain.elf] Error 1
errno is a global variable. that the C library probably wants to use for the soft float.
int __errno;
double sqrt(double x);
double notmain ( double a )
{
return(sqrt(a));
}
and now the tool is happy
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/softfp/libm.a
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
but this is hard float not soft.
00008024 <notmain>:
8024: eaffffff b 8028 <sqrt>
00008028 <sqrt>:
8028: e52de004 push {lr} ; (str lr, [sp, #-4]!)
802c: ed2d8b02 vpush {d8}
8030: e1a02000 mov r2, r0
8034: e1a03001 mov r3, r1
8038: e24dd02c sub sp, sp, #44 ; 0x2c
803c: ec432b18 vmov d8, r2, r3
8040: eb000038 bl 8128 <__ieee754_sqrt>
8044: e59f30d4 ldr r3, [pc, #212] ; 8120 <sqrt+0xf8>
8048: eeb48b48 vcmp.f64 d8, d8
804c: e1d3c0d0 ldrsb ip, [r3]
8050: eef1fa10 vmrs APSR_nzcv, fpscr
You get the idea though as to what the path to take to solve this is. You need a properly matched/built library then you need to link it. Keil and others simply do that for you in the toolchain, matching things based on the project. And/or a C library that is integrated with the toolchain.
Building for hard float
arm-none-eabi-as --warn --fatal-warnings -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfp start.s -o start.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mhard-float -mfpu=vfp -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles start.o notmain.o -T memmap -o notmain.elf /home/so/gcc-arm-none-eabi-9-2019-q4-major/lib/gcc/arm-none-eabi/9.2.1/libgcc.a /home/so/gcc-arm-none-eabi-9-2019-q4-major/arm-none-eabi/lib/arm/v5te/hard/libm.a
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy --srec-forceS3 notmain.elf -O srec notmain.srec
arm-none-eabi-objcopy notmain.elf -O binary kernel.img
tool is happy.
00008024 <notmain>:
8024: eaffffff b 8028 <sqrt>
00008028 <sqrt>:
8028: e52de004 push {lr} ; (str lr, [sp, #-4]!)
802c: ed2d8b02 vpush {d8}
8030: eeb08b40 vmov.f64 d8, d0
8034: e24dd02c sub sp, sp, #44 ; 0x2c
8038: eb000038 bl 8120 <__ieee754_sqrt>
803c: eeb48b48 vcmp.f64 d8, d8
8040: e59f30d0 ldr r3, [pc, #208] ; 8118 <sqrt+0xf0>
8044: e1d310d0 ldrsb
Would have to make this a real application main calls another function that has a call to sqrt in it. And then run it on hardware and/or examine these instructions. Or even better get a C library implementation of sqrt and build it in the project so that it matches the target and instruction sets. (same story with the libgcc calls as needed, test them or build them).

Why I cannot compile with -fPIE but can with -fPIC?

I have one interesting compilation problem.
At first, please see code to be compiled.
$ ls
Makefile main.c sub.c sub.h
$ gcc -v
...
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
## Makefile
%.o: CFLAGS+=-fPIE #[2]
main.so: main.o sub.o
$(CC) -shared -fPIC -o $# $^
//main.c
#include "sub.h"
int main_func(void){
sub_func();
subsub_func();
return 0;
}
//sub.h
#pragma once
void subsub_func(void);
void sub_func(void);
//sub.c
#include "sub.h"
#include <stdio.h>
void subsub_func(void){
printf("%s\n", __func__);
}
void sub_func(void){
subsub_func();//[1]
printf("%s\n", __func__);
}
And I compile this and got a error as below
$ LANG=en make
cc -fPIE -c -o main.o main.c
cc -fPIE -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
/usr/bin/ld: sub.o: relocation R_X86_64_PC32 against symbol `subsub_func' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [main.so] Error 1
And after this, I modified the code(removing a line [1]/using -fPIC instead of -PIE[2]) and then successfully compiled these.
$ make #[1]
cc -fPIE -c -o main.o main.c
cc -fPIE -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
$ make #[2]
cc -fPIC -c -o main.o main.c
cc -fPIC -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
Why did this phenomenon happened?
I have heard that calling a function within an object is done through PLT when it is compiled with -fPIC but done by jumping to the function directly when it si compiled with -fPIE.
I guessed that the function call mechanism with -fPIE refrains from relocation.
But I would like to know exact and accurate explanation of that.
Would you help me?
Thank you, all.
The only code generation difference between -fPIC and -fPIE for the code shown is in the call from sub_func to subsub_func. With -fPIC, that call goes through the PLT; with -fPIE, it's a direct call. In assembly dumps (cc -S), that looks like this:
--- sub.s.pic 2017-12-07 08:10:00.308149431 -0500
+++ sub.s.pie 2017-12-07 08:10:08.408068650 -0500
## -34,7 +34,7 ## sub_func:
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
- call subsub_func#PLT
+ call subsub_func
leaq __func__.2258(%rip), %rsi
leaq .LC0(%rip), %rdi
movl $0, %eax
In unlinked object files, it's a change of relocation type:
--- sub.o.dump.pic 2017-12-07 08:13:54.197775840 -0500
+++ sub.o.dump.pie 2017-12-07 08:13:54.197775840 -0500
## -22,7 +22,7 ##
1f: 55 push %rbp
20: 48 89 e5 mov %rsp,%rbp
23: e8 00 00 00 00 callq 28 <sub_func+0x9>
- 24: R_X86_64_PLT32 subsub_func-0x4
+ 24: R_X86_64_PC32 subsub_func-0x4
28: 48 8d 35 00 00 00 00 lea 0x0(%rip),%rsi # 2f <sub_func+0x10>
2b: R_X86_64_PC32 .rodata+0x14
2f: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 36 <sub_func+0x17>
And, on this architecture, when you link a shared library using cc -shared, the linker does not allow the input object files to contain R_X86_64_PC32 relocations targeting global symbols, thus the error you observed when you used -fPIE instead of -fPIC.
Now, you are probably wondering why direct calls within a shared library are not allowed. In fact, they are allowed, but only when the callee is not a global. For instance, if you declared subsub_func with static, then the call target would be resolved by the assembler and there would be no relocation at all in the object file, and if you declared it with __attribute__((visibility("hidden"))) then you would get an R_X86_64_PC32 relocation but the linker would allow it because the callee is no longer exported from the library. But in both cases subsub_func would not be callable from outside the library anymore.
Now you're probably wondering what it is about global symbols that means you have to call them through the PLT from a shared library. This has to do with an aspect of the ELF symbol resolution rules that you may find surprising: any global symbol in a shared library can be overridden by either the executable, or an earlier library in the link order. Concretely, if we leave your sub.h and sub.c alone but make main.c read like this:
//main.c
#include "sub.h"
#include <stdio.h>
void subsub_func(void) {
printf("%s (main)\n", __func__);
}
int main(void){
sub_func();
subsub_func();
return 0;
}
so it's now got the an official executable entry point in it but also a second definition of subsub_func, and we compile sub.c into a shared library and main.c into an executable that calls it, and run the whole thing, like this
$ cc -fPIC -c sub.c -o sub.o
$ cc -c main.c -o main.o
$ cc -shared -Wl,-soname,libsub.so.1 sub.o -o libsub.so.1
$ ln -s libsub.so.1 libsub.so
$ cc main.o -o main -L. -lsub
$ LD_LIBRARY_PATH=. ./main
the output will be
subsub_func (main)
sub_func
subsub_func (main)
That is, both the call from main to subsub_func, and the call from sub_func, within the library, to subsub_func, were resolved to the definition in the executable. For that to be possible, the call from sub_func must go through the PLT.
You can change this behavior with an additional linker switch, -Bsymbolic.
$ cc -shared -Wl,-soname,libsub.so.1 -Wl,-Bsymbolic sub.o -o libsub.so.1
$ LD_LIBRARY_PATH=. ./main
subsub_func
sub_func
subsub_func (main)
Now the call from sub_func is resolved to the definition within the library. In this case, using -Bsymbolic allows sub.c to be compiled with -fPIE instead of -fPIC, but I don't recommend you do that. There are other effects of using -fPIE instead of -fPIC, such as changing how access to thread-local storage needs to be done, and those cannot be worked around with -Bsymbolic.

Assembly function call from c

I cannot combine my kernel_entry.asm and main.c. My main.c calls an asm function Sum. Both nasm and gcc compiles respective files. However, the linker gives an error.
Kernel_entry.asm:
[bits 32]
[extern _start]
[global _Sum]
....
_Sum:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ecx, [ebp+12]
add eax, ecx
pop ebp
ret
main.c:
....
extern int Sum();
void start() {
....
int x = Sum(4, 5);
....
}
To compile source files, I use following commands:
nasm kernel_entry.asm -f win32 -o kernel_entry.o
gcc -ffreestanding -c main.c -o main.o
....
ld -T NUL -o kernel.tmp -Ttext 0x1000 kernel_entry.o main.o mem.o port_in_out.o screen.o idt.o
Linker gives following error:main.o:main.c:(.text+0xa82): undifened reference to 'Sum'. I tried everything but couldn't find any solution. When I remove asm function call from main.c, it works.
The TL;DR version of the answer is that mixing nasm's -f win32 generates an object file that is not compatible with the GNU toolchain on Windows - you need to use -f elf if you want to link using ld. That is described in NASM's documentation here under sections 7.5 and 7.9.
The hint for me was that by running nm kernel_entry.o generated:
00000000 a .absolut
00000000 t .text
00000001 a #feat.00
U _start
U _Sum
Which basically shows Sum as an undefined symbol. After compiling as ELF, I got:
U _start
00000000 T _Sum
indicating Sum as a recognised symbol in the text section.

Assembling and Linking gcc generated assembly on Mac OS X

If I have the following C Code
int main()
{
return 77;
}
I can generate asm code with the -S option on clang to get the following (Intel syntax)
$clang -O0 -mllvm --x86-asm-syntax=intel main.c -S
the code then is
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## #main
.cfi_startproc
## BB#0:
push RBP
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp4:
.cfi_def_cfa_register rbp
mov EAX, 77
mov DWORD PTR [RBP - 4], 0
pop RBP
ret
.cfi_endproc
.subsections_via_symbols
However neither as, gas or nasm will generate an object file to link with ld... does clang or gcc generate actual good "ready to go" asm? gcc's default assembler is gas (which isn't even installed on mac os x...? isn't it the same for clang).
So how do I manually assemble the asm code and then link it?
Yes, gcc generates correct assembly code.
It's just as.
You should be able to assemble it with as and link with ld:
as -o example.o example.s
ld -macosx_version_min 10.8.0 -o example example.o -lSystem
or, probably more easily, by using gcc or clang as the frontend:
cc -o example example.s
Edit: Complete working example:
$ cat example.c
int main()
{
return 77;
}
$ gcc -S example.c -o example.s
$ as -o example.o example.s
$ ld -macosx_version_min 10.8.0 -o example example.o -lSystem
$ ./example
$ echo $?
77
OK, since you're using clang, you might want to be using its assembler, too. Mixing & matching toolchains usually ends in tears:
$ clang -cc1as -filetype obj -mllvm --x86-asm-syntax=intel -o example.o example.s
$ ld -macosx_version_min 10.8.0 -o example example.o -lSystem
Since you're using clang, why not compile it with clang instead of gcc?
clang main.s -mllvm --x86-asm-syntax=intel -o main
Try calling gcc with the .s file.

Resources