Problems compiling assembly file - Error: undefined reference to `function name' - c

I am trying to take a look at a test program my professor gave us, but I am having trouble compiling it. I am on Ubuntu 14.04. I am compiling it with
gcc -Wall test.c AssemblyFunction.S -m32 -o test
I was having problems running the code on a 64-bit machine and read that adding -Wall and -m32 will allow it to work. Doing that fixed the first problem I had, but now I am getting the error: undefined reference to `addnumbersinAssembly'.
Here is the C file
#include <stdio.h>
#include <stdlib.h>
extern int addnumbersinAssembly(int, int);
int main(void)
{
int a, b;
int res;
a = 5;
b = 6;
// Call the assembly function to add the numbers
res = addnumbersinAssembly(a,b);
printf("\nThe sum as computed in assembly is : %d", res);
return(0);
}
And here is the assembly file
.global _addnumbersinAssembly
_addnumbersinAssembly:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp), %eax
addl 12(%ebp), %eax # Add the args
movl %ebp,%esp
popl %ebp
ret
Thank you for your time. I have been trying to figure this out for hours, so I appreciate any help.

I believe that with GCC you are going to want to remove the _ in your assembler file. So these lines:
.global _addnumbersinAssembly
_addnumbersinAssembly:
Should be:
.global addnumbersinAssembly
addnumbersinAssembly:
More information on this issue can be found in this StackOverflow question/answer.
The -m32 compile parameter is needed because the assembly code you have needs to be rewritten to support some 64 bit operations. In your case it was stack operations. The -Wall isn't needed to compile but it does turn on many more warnings.

Related

Compiling error with ld in gcc : "undefined reference to ..."

I'm on Windows 11 in 64 bit machine and for didactic purpose I'm trying to compile in 32 bit a C code (.c) with linked Assebly code (.s), with the following command:
gcc -m32 <file.c> <file.s> -o <name_file>
but the compilation failed reporting the following error:
C:\Users\david\AppData\Local\Temp\ccQPXOVR.o:e2_main.c:(.text+0x1a): undefined reference to f collect2.exe: error: ld returned 1 exit status
The MinGW version that I use is: x86_64-8.1.0-posix-sjlj-rt_v6-rev0
I think the problem is in the ld linker, because compiling the same files but in 64 bits through the following command: gcc -m64 <file.c> <file.s> -o <name_file> does not give me an error (but it is not what I need, I need to compile them in 32 bits).
Below I report the code files that I should compile
<file.c>
#include <stdio.h>
int f(int x);
int score, trials;
void test(int x, int c) {
trials++;
int r = f(x);
printf("Test %d: %d [corretto: %d]\n", trials, r, c);
score += r == c;
}
int main() {
test(3, -2);
test(4, 5);
test(7, 50);
test(17, 460);
printf("Risultato: %d/%d\n", score, trials);
return 0;
}
<file.s>
.globl f
f:
movl 4(%esp), %ecx
movl %ecx, %eax
imull $2, %eax
imull %ecx, %eax
movl $7, %edx
imull %ecx, %edx
subl %edx, %eax
incl %eax
ret
Any ideas on how I can fix it?
I would hugely appreciate any suggestions or guidance on what to do or try next, as I am a little stuck and unsure from here.
I also try to compile an other C code with -m32 flag without linking anything and it seems to have worked.
I try to install i686-8.1.0-release-posix-sjlj-rt_v6-rev0 but it doesn't seem to change anything when I compile with -m32 .

Error linking code with `floor();`, `ceil();` and `pow();` [duplicate]

This question already has answers here:
Why do you have to link the math library in C?
(14 answers)
Why is -lm not necessary in some cases when compiling and linking C code?
(3 answers)
Closed 6 years ago.
I am coding under GNU/Linux Debian 8.5
I have a simple program.
If I compile this with gcc prog.c it is OK!
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
int main(int argc, char const *argv[]) {
float _f = 3.1415f;
floor(_f);
ceil(_f);
return 0;
}
Bud if I add pow(), it says that it cannot find pow and I need to add gcc prog.c -lm to make it right.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
int main(int argc, char const *argv[]) {
float _f = 3.1415f;
floor(_f);
ceil(_f);
pow(_f, 2);
return 0;
}
If I am right, the pow(), ceil(), floor() are all from <math.h>?
So why don't floor() and ceil() throw a compilation error, and pow() does, without -lm flag?
Technically all of them require -lm to work. All of their man pages include this line:
Link with -lm.
But yours is not a compiler error but a linker error, that is your program compiles fine, but then when linking if you don't use -lm it is unable to find the implementation of pow() but it actually finds the implementation of ceil().
That is probably because in your architecture/configuration ceil() is an inline or intrinsic function, maybe there is a simple CPU instruction to do it, so no library is necessariy. But pow() is not so you need to link libm.
UPDATE: I've just made some experiments, and with -O0 all your functions require the -lm but with -O2 only pow(). Tinkering about that I found the file /usr/include/bits/mathinline.h with the inline implementations of ceil() and floor()...
The compiler only complains about pow() and not floor() or ceil() probably because it generates inline code for floor() and ceil() and an external call for pow() which cannot be resolved at link time because you forgot the m library on the command line: -lm stands for link with libm.a.
Incidentally, since you do not store the return value of these functions, the compiler might use its intrinsic knowledge of these pure functions (conveyed in some way in <math.h>) to remove the calls altogether. It might do that for ceil() and floor() and not for pow(), which would also explain the observed behavior.
Indeed, as can be verified on http://gcc.goldbolt.org/#, with no command line options, your code compiles as:
main:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movss .LC0(%rip), %xmm0
movss %xmm0, -4(%rbp)
cvtss2sd -4(%rbp), %xmm0
movsd .LC1(%rip), %xmm1
call pow
movl $0, %eax
leave
ret
.LC0:
.long 1078529622
.LC1:
.long 0
.long 1073741824
For some reason, the compiler generates inline code only for floor and ceil, as observed.
While with -O2 it removes everything:
main:
xorl %eax, %eax
ret
If you modify the code to store the values into global variables, library calls to floor(), ceil() and pow() are generated without optimization and the values are computed by the compiler if you optimize with -O2.
The error you get is a linking error, not a compilation error.
Floor and ceil might be in some other library, generally the compiler is not required to diagnose missing headers or libraries.

Combining c and assembler code

This is my C code:
#include <stdio.h>
void sum();
int newAlphabet;
int main(void)
{
sum();
printf("%d\n",newAlphabet);
}
And this is my assembler code:
.globl _sum
_sum:
movq $1, %rax
movq %rax, _newAlphabet
ret
I'm trying to call the sum function, from my main function, to set newAlphabet equal to 1, but when I compile it (gcc -o test assembler.c assembler.s, compiled on a 64-bit OSX laptop) I get the following errors:
32-bit absolute addressing is not supported for x86-64
cannot do signed 4 byte relocation
both caused by the line "movq %rax, _newAlphabet"
I'm sure I'm making a very basic mistake. Can anyone help? Thanks in advance.
EDIT:
Here are the relevant portions of the C code once it has been translated to assembler:
.comm _newAlphabet,4,2
...
movq _newAlphabet#GOTPCREL(%rip), %rax
Mac OS X uses position-independent executables by default, which means your code can't use constant global addresses for variables. Instead you'll need to access globals in an IP-relative way. Just change:
movq %rax, _newAlphabet
to:
mov %eax, _newAlphabet(%rip)
and you'll be set (I changed from 64 to 32 bit registers to match sizeof(int) on Mac OS X. Note that you also need a .globl _newAlphabet in there somewhere. Here's an example I just made based on your code (note that I initialized newAlphabet to prove it works):
example.c:
#include <stdio.h>
void sum(void);
int newAlphabet = 2;
int main(void)
{
printf("%d\n",newAlphabet);
sum();
printf("%d\n",newAlphabet);
return 0;
}
assembly.s:
.globl _sum
.globl _newAlphabet
_sum:
movl $1, _newAlphabet(%rip)
ret
Build & run:
$ cc -c -o example.o example.c
$ cc -c -o assembly.o assembly.s
$ cc -o example example.o assembly.o
$ ./example
2
1

thread local storage in assembly

I want to increment a TLS variable in assembly but is gives a segmentation fault in the assembly code. I don't want to let compiler change any other register or memory. Is there a way to do this without using gcc input and output syntax?
__thread unsigned val;
int main() {
val = 0;
asm("incl %gs:val");
return 0;
}
If you really really need to be able to do this for some reason, you should access a thread-local variable from assembly language by preloading its address in C, like this:
__thread unsigned val;
void incval(void)
{
unsigned *vp = &val;
asm ("incl\t%0" : "+m" (*vp));
}
This is because the code sequence required to access a thread-local variable is different for just about every OS and CPU combination supported by GCC, and also varies if you're compiling for a shared library rather than an executable (i.e. with -fPIC). The above construct allows the compiler to emit the correct code sequence for you. In cases where it is possible to access the thread-local variable without any extra instructions, the address generation will be folded into the assembly operation. By way of illustration, here is how gcc 4.7 for x86/Linux compiles the above in several different possible modes (I've stripped out a bunch of assembler directives in all cases, for clarity)...
# -S -O2 -m32 -fomit-frame-pointer
incval:
incl %gs:val#ntpoff
ret
# -S -O2 -m64
incval:
incl %fs:val#tpoff
ret
# -S -O2 -m32 -fomit-frame-pointer -fpic
incval:
pushl %ebx
call __x86.get_pc_thunk.bx
addl $_GLOBAL_OFFSET_TABLE_, %ebx
leal val#tlsgd(,%ebx,1), %eax
call ___tls_get_addr#PLT
incl (%eax)
popl %ebx
ret
# -S -O2 -m64 -fpic
incval:
.byte 0x66
leaq val#tlsgd(%rip), %rdi
.value 0x6666
rex64
call __tls_get_addr#PLT
incl (%rax)
ret
Do realize that all four examples would be different if I'd compiled for x86/OSX, and different yet again for x86/Windows.

Bus error 10 with assembly code + general questions

Okay so I'm trying to create a program for fun which counts the bits in a number
What I Want:
As I said, a program which counts the bits in a given number.
(for instance countsbits(1)=countbits(2)=countbits(4)=1).
What I Get:
I get the correct output but now I receive an error message
"Segmentation fault:11". I ran someone else's program and they did not receive this error, so clearly it's my wrongdoing. How can I amend this so I don't get a segmentation fault?
The command I enter is:
gcc -m32 -mstackrealign countbit.c countbits.s
The program compiles just fine but when I try to run the a.out generated by the program I get the error. Any ideas?
My Code:
.text
.data
.globl _x
.globl _countbits
_countbits:
pushl %ebp
movl %esp,%ebp
pushl %ebx
mov $0,%edx
mov $0,%eax
mov 8(%ebp),%ebx
LOOP:
mov $1,%ecx
and %ebx,%ecx
add %ecx,%eax
shrl $1,%ebx
add $1,%edx
cmp $32,%edx
jle LOOP
pop %ebx
pop %ebp
ret
and the code that calls it from C:
#include <stdio.h>
int foo (int x){
int p=countbits(x);
printf("The count is: %d",p);
}
main(){
int x=16;
foo(16);
}
You can't really ask a question about assembly code without mentioning what kind of processor assembly code you're talking about. For example, many processors have a dedicated instruction for counting number of bits set. For example, see POPCNT

Resources