Issue with gcc on Ubuntu Bash on windows with math library - c

I have a makefile that uses "-lm" flag to include the math library. I also included #include for each .c file.
I am still getting error and "undefined reference" to the math such as exp, floor, and pow etc.
Using bash on windows Ubuntu.
Copy of my terminal output:
labyu#DESKTOP-U037B9F:~/software/BICseq2/NBICseq-norm_v0.2.4$ make
gcc -g -O2 -Wall -lm -c -o combineFile/combine.o combineFile/combine.c
gcc -g -O2 -Wall -lm -c -o lib/read.o lib/read.c
lib/read.c: In function ‘read_table’:
lib/read.c:74:14: warning: variable ‘flag’ set but not used [-Wunused-but-set-variable]
int i=0,j=0,flag=1,low_mmry = 40000, is_num=0,k;
^
gcc -g -O2 -Wall -lm combineFile/combine.o lib/read.o -o combineFile/combineFile
gcc -g -O2 -Wall -lm -c -o DataPrepare/DtaPrep.o DataPrepare/DtaPrep.c
gcc -g -O2 -Wall -lm -c -o lib/statlib.o lib/statlib.c
gcc -g -O2 -Wall -lm DataPrepare/DtaPrep.o lib/read.o lib/statlib.o -o DataPrepare/PrepPois
DataPrepare/DtaPrep.o: In function `print_oneline':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:593: undefined reference to `pow'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:591: undefined reference to `log'
DataPrepare/DtaPrep.o: In function `calculate_bias':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:685: undefined reference to `pow'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:690: undefined reference to `exp'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:681: undefined reference to `log'
DataPrepare/DtaPrep.o: In function `fprint_gc_bin':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:810: undefined reference to `floor'
DataPrepare/DtaPrep.o: In function `fprintf_predicted':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:850: undefined reference to `exp'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:860: undefined reference to `floor'
DataPrepare/DtaPrep.o: In function `calculate_bias':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/DataPrepare/DtaPrep.c:749: undefined reference to `exp'
lib/statlib.o: In function `db_shuffle':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:56: undefined reference to `floor'
lib/statlib.o: In function `db_shuffle_int':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:71: undefined reference to `floor'
lib/statlib.o: In function `rgamma1':
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:99: undefined reference to `log'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:100: undefined reference to `pow'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:103: undefined reference to `pow'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:104: undefined reference to `exp'
/home/labyu/software/BICseq2/NBICseq-norm_v0.2.4/lib/statlib.c:90: undefined reference to `log'
collect2: error: ld returned 1 exit status
make: *** [PrepPois] Error 1
But, when I make a sample program, such as this: test.c
#include <stdio.h>
#include <math.h>
int main(void)
{
int number;
number = pow(10,2);
printf("%d\n", number);
return 0;
}
I can use gcc test.c even without the -lm flag and it compiles fine.
Is this a bug?

In your test case, since all data is constant, it seems the compiler computes directly the value (it may depend on the compiler, but recent versions of gcc seem to handle this fine)
When disassembling the code (x86) we see it clearly
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 30 sub $0x30,%rsp
8: e8 00 00 00 00 callq d <main+0xd>
direct 100 value passed to printf at the line below
d: c7 45 fc 64 00 00 00 movl $0x64,-0x4(%rbp)
14: 8b 45 fc mov -0x4(%rbp),%eax
17: 89 c2 mov %eax,%edx
19: 48 8d 0d 00 00 00 00 lea 0x0(%rip),%rcx # 20 <main+0x20>
20: e8 00 00 00 00 callq 25 <main+0x25>
25: b8 00 00 00 00 mov $0x0,%eax
2a: 90 nop
2b: 48 83 c4 30 add $0x30,%rsp
2f: 5d pop %rbp
30: c3 retq
31: 90 nop
i have changed the code to this:
#include <stdio.h>
#include <math.h>
int main(void)
{
int number;
int v=10;
number = pow(v,2);
printf("%d\n", number);
return 0;
}
And now when I nm the file I get:
>nm simplemath.o
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
U __main
0000000000000000 T main
U pow
U printf
Before I introduced the variable, the pow symbol was not referenced. The compiler did the math statically.
The disassembly shows a more complex code, using float registers and all.
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 40 sub $0x40,%rsp
8: e8 00 00 00 00 callq d <main+0xd>
d: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
14: 66 0f ef c0 pxor %xmm0,%xmm0
18: f2 0f 2a 45 fc cvtsi2sdl -0x4(%rbp),%xmm0
1d: 48 b8 00 00 00 00 00 movabs $0x4000000000000000,%rax
24: 00 00 40
27: 48 89 45 e8 mov %rax,-0x18(%rbp)
2b: f2 0f 10 4d e8 movsd -0x18(%rbp),%xmm1
30: e8 00 00 00 00 callq 35 <main+0x35> <== the linker wil add the call to pow here
35: f2 0f 2c c0 cvttsd2si %xmm0,%eax
39: 89 45 f8 mov %eax,-0x8(%rbp)
3c: 8b 45 f8 mov -0x8(%rbp),%eax
3f: 89 c2 mov %eax,%edx
41: 48 8d 0d 00 00 00 00 lea 0x0(%rip),%rcx # 48 <main+0x48>
48: e8 00 00 00 00 callq 4d <main+0x4d>
4d: b8 00 00 00 00 mov $0x0,%eax
52: 90 nop
53: 48 83 c4 40 add $0x40,%rsp
57: 5d pop %rbp
58: c3 retq
But to my surprise, no need of -lm, it links OK without it.
Newest gcc versions must include it by default since it's often used. Maybe someone can confirm. You version seems to need it, mine doesn't (gcc 4.9.4)

Related

Question about relocation entries in assembly code

I write 2 C programs : main.c and sum.c.
Here is main.c :
int array[2] = {1, 2};
int main() {
int val = sum(array, 2);
return val;
}
Here is sum.c :
int sum(int* a, int n) {
int i, s = 0;
for (i = 0; i < n; i++) {
s += a[i];
}
return s;
}
I use command gcc -c -o main.o main.c and objdump -d -r main.o>main.d and I get :
main.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 48 83 ec 08 sub $0x8,%rsp
8: be 02 00 00 00 mov $0x2,%esi
d: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 14 <main+0x14>
10: R_X86_64_PC32 array-0x4
14: b8 00 00 00 00 mov $0x0,%eax
19: e8 00 00 00 00 callq 1e <main+0x1e>
1a: R_X86_64_PLT32 sum-0x4
1e: 48 83 c4 08 add $0x8,%rsp
22: c3 retq
What does 1e: R_X86_64_PLT32 sum-0x4 mean? Shouldn't it be sum-0x22 because at that time the RIP is 0x22?
And also what does 0x4 in 10: R_X86_64_PC32 array-0x4 stand for?
And one more question : My computer is 64-bit but why the address is 32-bit in the assembly code?

dump_stack() in Linux kernel doesn't print the addresses of functions

I have a test Linux kernel module which prints the dump_stack(). But it prints an incomplete trace as it does not have the function addresses printed. I use a Ubuntu 16.04.7 LTS with 4.15.0-142-generic kernel and CONFIG_DEBUG_INFO=y is set in /boot/config-4.15.0-142-generic.
My questions:
(1) Why the function's address is not printed? I can dump the symbol table using objdump -t.
(2) Trace shows that dump_stack() is called from module_level_init . However it is module_level_init()->module_level_2()->module_level_3()
Following is the dmesg output:
[ 1347.807370] CPU: 7 PID: 13262 Comm: insmod Tainted: P OE 4.15.0-142-generic #146~16.04.1-Ubuntu
[ 1347.807371] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[29020.752090] Call Trace:
[29020.752096] dump_stack+0x6d/0x8b
[29020.752097] ? 0xffffffffc0730000
[29020.752099] module_level_init+0x1a/0x1000 [kern]
[29020.752102] do_one_initcall+0x55/0x1b0
[29020.752103] ? _cond_resched+0x1a/0x50
[29020.752105] ? kmem_cache_alloc_trace+0x165/0x1c0
[29020.752106] do_init_module+0x5f/0x222
[29020.752108] load_module+0x1894/0x1ea0
[29020.752111] ? ima_post_read_file+0x83/0xa0
[29020.752112] SYSC_finit_module+0xe5/0x120
[29020.752113] ? SYSC_finit_module+0xe5/0x120
[29020.752115] SyS_finit_module+0xe/0x10
[29020.752116] do_syscall_64+0x73/0x130
The kernel module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
int module_level_3(void)
{
dump_stack();
return 0;
}
int module_level_2(void)
{
module_level_3();
return 0;
}
static int __init module_level_init(void)
{
printk(KERN_INFO "Hello, world\n");
module_level_2();
return 0;
}
static void __exit module_level_exit(void)
{
printk(KERN_INFO "Goodbye, world\n");
}
module_init(module_level_init);
module_exit(module_level_exit);
MODULE_LICENSE("GPL");
Makefile:
obj-m += kern.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
objdump
#objdump -Sdlr kern.ko
kern.ko: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <module_level_3>:
module_level_3():
0: e8 00 00 00 00 callq 5 <module_level_3+0x5>
1: R_X86_64_PC32 __fentry__-0x4
5: 55 push %rbp
6: 48 89 e5 mov %rsp,%rbp
9: e8 00 00 00 00 callq e <module_level_3+0xe>
a: R_X86_64_PC32 dump_stack-0x4
e: 31 c0 xor %eax,%eax
10: 5d pop %rbp
11: c3 retq
12: 0f 1f 40 00 nopl 0x0(%rax)
16: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
1d: 00 00 00
0000000000000020 <module_level_2>:
module_level_2():
20: e8 00 00 00 00 callq 25 <module_level_2+0x5>
21: R_X86_64_PC32 __fentry__-0x4
25: 55 push %rbp
26: 48 89 e5 mov %rsp,%rbp
29: e8 00 00 00 00 callq 2e <module_level_2+0xe>
2a: R_X86_64_PC32 dump_stack-0x4
2e: 31 c0 xor %eax,%eax
30: 5d pop %rbp
31: c3 retq
Disassembly of section .init.text:
0000000000000000 <init_module>:
module_level_init():
0: e8 00 00 00 00 callq 5 <init_module+0x5>
1: R_X86_64_PC32 __fentry__-0x4
5: 55 push %rbp
6: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
9: R_X86_64_32S .rodata.str1.1
d: 48 89 e5 mov %rsp,%rbp
10: e8 00 00 00 00 callq 15 <init_module+0x15>
11: R_X86_64_PC32 printk-0x4
15: e8 00 00 00 00 callq 1a <init_module+0x1a>
16: R_X86_64_PC32 dump_stack-0x4
1a: 31 c0 xor %eax,%eax
1c: 5d pop %rbp
1d: c3 retq
Disassembly of section .exit.text:
0000000000000000 <cleanup_module>:
module_level_exit():
0: 55 push %rbp
1: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
4: R_X86_64_32S .rodata.str1.1+0x10
8: 48 89 e5 mov %rsp,%rbp
b: e8 00 00 00 00 callq 10 <cleanup_module+0x10>
c: R_X86_64_PC32 printk-0x4
10: 5d pop %rbp
11: c3 retq

fpic and O3 optimization flags

I'm trying to compile main.c which uses libnothing.so. Here is the source code:
main.c
#include "nothing.h"
int main(void)
{
doAlmostNothing();
return 0;
}
nothing.c
#include "nothing.h"
void doNothingStatic(void) {
volatile int x = 45;
x++;
}
void doNothing(void) {}
void doAlmostNothing(void)
{
doNothingStatic();
doNothing();
}
nothing.h
void doAlmostNothing(void);
First I compile nothing.c like this without fpic: gcc -c nothing.c I'll get this error: /usr/bin/ld: nothing.o: relocation R_X86_64_PC32 against symbol doNothing can not be used when making a shared object; recompile with -fPIC when building the .so gcc -shared nothing.o -o libnothing.so
But if I compile it using O3 gcc -c -O3 nothing.c I don't get the relocation error anymore.
Is -O3 adding fpic by default ?
EDIT
I changed a bit the code by adding void as suggested in the comments, removed static from doNothingStatic and add some dummy work in it.
Here is the console output when running the commands:
bil#bil-VirtualBox:~/Documents/test/linking$ gcc-7 -c nothing.c
bil#bil-VirtualBox:~/Documents/test/linking$ gcc-7 -shared nothing.o -o nothing.so
/usr/bin/ld: nothing.o: relocation R_X86_64_PC32 against symbol `doNothingStatic' 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
bil#bil-VirtualBox:~/Documents/test/linking$ gcc-7 -c -O3 nothing.c
bil#bil-VirtualBox:~/Documents/test/linking$ gcc-7 -shared nothing.o -o libnothing.so
bil#bil-VirtualBox:~/Documents/test/linking$ ls
libnothing.so main main.c main.o nothing.c nothing.h nothing.o libnothing.so
I also looked on the assembly that objdump provides:
without O3:
nothing.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <doNothingStatic>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: c7 45 fc 2d 00 00 00 movl $0x2d,-0x4(%rbp)
b: 8b 45 fc mov -0x4(%rbp),%eax
e: 83 c0 01 add $0x1,%eax
11: 89 45 fc mov %eax,-0x4(%rbp)
14: 90 nop
15: 5d pop %rbp
16: c3 retq
0000000000000017 <doNothing>:
17: 55 push %rbp
18: 48 89 e5 mov %rsp,%rbp
1b: 90 nop
1c: 5d pop %rbp
1d: c3 retq
000000000000001e <doAlmostNothing>:
1e: 55 push %rbp
1f: 48 89 e5 mov %rsp,%rbp
22: e8 00 00 00 00 callq 27 <doAlmostNothing+0x9>
27: e8 00 00 00 00 callq 2c <doAlmostNothing+0xe>
2c: 90 nop
2d: 5d pop %rbp
2e: c3 retq
with O3
nothing.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <doNothingStatic>:
0: c7 44 24 fc 2d 00 00 movl $0x2d,-0x4(%rsp)
7: 00
8: 8b 44 24 fc mov -0x4(%rsp),%eax
c: 83 c0 01 add $0x1,%eax
f: 89 44 24 fc mov %eax,-0x4(%rsp)
13: c3 retq
14: 66 90 xchg %ax,%ax
16: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
1d: 00 00 00
0000000000000020 <doNothing>:
20: f3 c3 repz retq
22: 0f 1f 40 00 nopl 0x0(%rax)
26: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
2d: 00 00 00
0000000000000030 <doAlmostNothing>:
30: c7 44 24 fc 2d 00 00 movl $0x2d,-0x4(%rsp)
37: 00
38: 8b 44 24 fc mov -0x4(%rsp),%eax
3c: 83 c0 01 add $0x1,%eax
3f: 89 44 24 fc mov %eax,-0x4(%rsp)
43: c3 retq
Indeed it seems the functions are inlined when using -O3
No, it is just that the function doNothing was inlined and thus there were no intra-module function calls left.
The relocation type means an absolute function or data access using a sign-extended 32-bit pointer, i.e. basically something within the first 2 GiB of virtual memory. When compiled with -O3 all function calls were inlined and therefore the calls using the relocations are not needed.
No, -O3 does not turn on -fPIC.
Here is the a list of flags turned on by the different optimization levels.
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

Why does global symbol in the same file needed to be relocated?

I had a C program for test: a.c
int a = 0;
static int fa_local()
{
a = 78;
int b;
int c;
}
int fa_global()
{
a = 7777;
fa_local();
}
int test()
{
a = 6666;
fa_global();
}
This is its relocation table after build:
[freeman#centos-7 link_symbol_test]$ gcc -c a.c
[freeman#centos-7 link_symbol_test]$ readelf -r a.o
Relocation section '.rela.text' at offset 0x5d0 contains 4 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000006 000900000002 R_X86_64_PC32 0000000000000000 a - 8
000000000016 000900000002 R_X86_64_PC32 0000000000000000 a - 8
000000000030 000900000002 R_X86_64_PC32 0000000000000000 a - 8
00000000003e 000a00000002 R_X86_64_PC32 0000000000000010 fa_global - 4
the relocation entry is the funcation call fa_global() in test(), which has offset 00000000003e.
[freeman#centos-7 link_symbol_test]$ objdump -dS a.o:
0000000000000010 <fa_global>:
int fa_global()
{
10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp
a = 7777;
14: c7 05 00 00 00 00 61 movl $0x1e61,0x0(%rip) # 1e <fa_global+0xe>
1b: 1e 00 00
fa_local();
1e: b8 00 00 00 00 mov $0x0,%eax
23: e8 d8 ff ff ff callq 0 <fa_local>
}
28: 5d pop %rbp
29: c3 retq
000000000000002a <test>:
int test()
{
2a: 55 push %rbp
2b: 48 89 e5 mov %rsp,%rbp
a = 6666;
2e: c7 05 00 00 00 00 0a movl $0x1a0a,0x0(%rip) # 38 <test+0xe>
35: 1a 00 00
fa_global();
38: b8 00 00 00 00 mov $0x0,%eax
3d: e8 00 00 00 00 callq 42 <test+0x18>
}
42: 5d pop %rbp
43: c3 retq
For fa_global(), it is in the same file.
why would this symbol need to be relocated,
while static symbol fa_local() doesn't?
2017.9.12 update: assembly code after optimization
[freeman#centos-7 relocation_test]$ gcc -fno-inline -O2 -c a.c
[freeman#centos-7 relocation_test]$ objdump -dS a.o
a.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <fa_local>:
0: c7 05 00 00 00 00 4e movl $0x4e,0x0(%rip) # a <fa_local+0xa>
7: 00 00 00
a: c3 retq
b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000000010 <fa_global>:
10: 31 c0 xor %eax,%eax
12: c7 05 00 00 00 00 61 movl $0x1e61,0x0(%rip) # 1c <fa_global+0xc>
19: 1e 00 00
1c: eb e2 jmp 0 <fa_local>
1e: 66 90 xchg %ax,%ax
0000000000000020 <test>:
20: 31 c0 xor %eax,%eax
22: c7 05 00 00 00 00 0a movl $0x1a0a,0x0(%rip) # 2c <test+0xc>
29: 1a 00 00
2c: e9 00 00 00 00 jmpq 31 <test+0x11>
But I still see the relocation entry:
000000000000002d R_X86_64_PC32 fa_global-0x0000000000000004
fa_local is a function. The compiler can determine its offset from the calling point. it uses a PC relative addressing mode for the call instruction so it does not need the absolute address and can emit the code directly.
Conversely, the a symbol is in a different section of memory, a writable segment whose offset cannot be determined at compile time. The linker does this in the relocation phase.
Right here the function is in the same file, but being non-static it can also be called from other files compiled later.
The compiler cannot know if that will happen, so it has to "prepare for the worst."

Functions and parameters in object file aren't correct?

#include <stdio.h>
void DispString(const char* charList)
{
puts(charList);
}
void main()
{
DispString("Hello, world!");
}
compile: gcc -c -g test.c -o test.o
link: gcc -o test test.o
Very simple, but when I use objdump to disassemble the object file(test.o), I got the following result:
objdump -d test.o:
boot.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <DispString>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 83 ec 10 sub $0x10,%rsp
8: 48 89 7d f8 mov %rdi,-0x8(%rbp)
c: 48 8b 45 f8 mov -0x8(%rbp),%rax
10: 48 89 c7 mov %rax,%rdi
13: e8 00 00 00 00 callq 18 <DispString+0x18>
18: c9 leaveq
19: c3 retq
000000000000001a <main>:
1a: 55 push %rbp
1b: 48 89 e5 mov %rsp,%rbp
1e: bf 00 00 00 00 mov $0x0,%edi
23: e8 00 00 00 00 callq 28 <main+0xe>
28: 5d pop %rbp
29: c3 retq
For the line 23, it passed 0 to %edi register, which is definitely wrong. It should pass the address of the "Hello, world!" string to it. And it called 28 <main+0xe>? The line 28 is just its next line, rather than function DispString(which is in line 0). Why could this happen? I've also looked into the final test file, in which all the values are just correct. So how could the linker know where to find those functions or strings?
You are only translating file so no linking has been done. Once linking jas been done, then and then DispString()'s address will be known to main and it will jump to there. So as suggested in one of the comments, use objdump with the comliled executable.

Resources