I'm trying to compile my program to run on linux but it doesn't work because of this error.
I compile with gcc -ansi -pedantic -Wall -m64 -o formula formula.c nCr.s and the error i get is:
/tmp/ccnNz7Jr.o: In function `main':
formula.c:(.text+0xc1): undefined reference to `nCr'
collect2: ld returned 1 exit status
make: *** [build] Error 1
Here's the code from the file formula.c
#include <stdio.h>
#include <stdlib.h>
#include "nCr.h"
#include <time.h>
#include <sys/time.h>
int main(int argc, const char * argv[])
{
int x = 0;
int y;
int z;
struct timeval start, end;
if (argv[1][0] == '-' && argv[1][1] == 'h') {
printf("Usage: formula <positive integer>");
} else {
y = atoi(argv[1]);
gettimeofday(&start, NULL);
printf("(1 + x)^%i = 1+", y);
if (y == 0)
printf("0");
if (y > 12) {
printf("%s\n","Please enter a number 12 or below. Anything higher results in overflow, the answer you want is not the answer you will get.");
}
for (; x <= y; x++) {
z = nCr(y, x);
if (z == -1) {
printf("Multiplication overflow. \n");
return 1;
} else {
if (x != 0)
printf("%i x^%i ",z , x);
if (x != y && x != 0)
printf("+ ");
}
}
gettimeofday(&end, NULL);
}
printf("\n%ld microseconds\n", ((end.tv_sec * 1000000 + end.tv_usec)
- (start.tv_sec * 1000000 + start.tv_usec)));
return 0;
}
ncr.h
#ifndef _NCR_H_
#define _NCR_H_
extern int Factorial(int n);
extern int nCr(int n, int r);
#endif /* _NCR_H_ */
and there's an assembly file called nCr.s
.globl _factorial
_factorial:
Leh_func_begin2:
pushq %rbp
Ltmp3:
movq %rsp, %rbp
Ltmp4:
movl %edi, -4(%rbp)
movl $1, -16(%rbp)
movl $1, -20(%rbp)
jmp LBB2_2
LBB2_1:
movl -16(%rbp), %eax
movl -20(%rbp), %ecx
imull %ecx, %eax
movl %eax, -16(%rbp)
movl -20(%rbp), %eax
addl $1, %eax
movl %eax, -20(%rbp)
LBB2_2:
movl -20(%rbp), %eax
movl -4(%rbp), %ecx
cmpl %ecx, %eax
jle LBB2_1
movl -16(%rbp), %eax
movl %eax, -12(%rbp)
movl -12(%rbp), %eax
movl %eax, -8(%rbp)
movl -8(%rbp), %eax
popq %rbp
ret
.globl _nCr
_nCr:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $32, %rsp
Ltmp2:
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %eax
xorb %cl, %cl
movl %eax, %edi
movb %cl, %al
callq _factorial
movl %eax, %ecx
movl %ecx, -20(%rbp)
movl -4(%rbp), %ecx
movl -8(%rbp), %edx
subl %edx, %ecx
movl %ecx, -24(%rbp)
movl -8(%rbp), %ecx
xorb %dl, %dl
movl %ecx, %edi
movb %dl, %al
callq _factorial
movl %eax, %ecx
movl -24(%rbp), %edx
xorb %sil, %sil
movl %edx, %edi
movb %sil, %al
movl %ecx, -32(%rbp)
callq _factorial
movl %eax, %ecx
movl -32(%rbp), %esi
imull %ecx, %esi
movl %esi, -28(%rbp)
movl -20(%rbp), %ecx
movl -28(%rbp), %esi
movl %ecx, %eax
cltd
idivl %esi
movl %eax, %ecx
movl %ecx, -16(%rbp)
movl %ecx, -12(%rbp)
movl -12(%rbp), %eax
addq $32, %rsp
popq %rbp
ret
Any help is greatly appreciated, can't seem to figure out why it's not compiling. It compiles just fine on mac but I need to get it run on linux.
GCC is not able to find extern int Factorial(int n); and extern int nCr(int n, int r); definitions because they are called _factorial: and _nCr: in your asm file. Change those labels to match the decl and your code will compile.
I noticed that you have only one call of nCr in the main function, so I think it is better to change decls in your .h. So your nCr.h will be:
#ifndef _NCR_H_
#define _NCR_H_
extern int _factorial(int n);
extern int _nCr(int n, int r);
#endif /* _NCR_H_ */
And you have to call _nCr(...) at main.
Related
So I'm learning how to convert the assembly into readable C code. The assembly is as follows...
Consider the compiler places the C variables: a at -4(%rbp), b at -8(%rbp), and c at -12(rbp).
file "main.c"
.text
.globl main
.type main, #function
main:
endbr64
pushq %rbp
movq %rsp, %rbp
movl $10, -12(%rbp)
movl $20, -4(%rbp)
movl $1, -8(%rbp)
.L4:
cmpl $1, -12(%rbp)
je .L7
movl -8(%rbp), %eax
imull -12(%rbp), %eax
movl %eax, -8(%rbp)
subl $1, -12(%rbp)
jmp .L4
.L7:
nop
movl -4(%rbp), %eax
imull -8(%rbp), %eax
movl %eax, -4(%rbp)
movl $0, %eax
popq %rbp
ret
This is what I have so far.
int c = 10;
int a = 20;
int b = 1;
for(c = 10; c > 1; c--)
{
int x = b;
x = c * x;
b = x;
}
Not completely sure how correct that is. The part that confuses me the most is the appearance (from what seems like out of nowhere) of eax. When eax appears, should I just assume that it is some other random variable? (hence the integer x I introduced)
I have a C program which has a function decod and the function has the following statements.
My decode.c script:
int decod(int x, int y, int z) {
int ty = y;
ty = ty - z;
int py = ty;
py = py << 31;
py = py >> 31;
ty = ty * x;
py = py ^ ty;
}
The assembly code of this program (generated by gcc -S decod.c) shows the following code.
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movl %edx, -28(%rbp)
movl -24(%rbp), %eax
movl %eax, -8(%rbp)
movl -28(%rbp), %eax
subl %eax, -8(%rbp)
movl -8(%rbp), %eax
movl %eax, -4(%rbp)
sall $31, -4(%rbp)
sarl $31, -4(%rbp)
movl -8(%rbp), %eax
imull -20(%rbp), %eax
movl %eax, -8(%rbp)
movl -8(%rbp), %eax
xorl %eax, -4(%rbp)
popq %rbp
.cfi_def_cfa 7, 8
ret
But, I want the program generate an assembly file with only the following lines of code.
subl %edx, %esi
movl %esi, %eax
sall $31, %eax
sarl $31, %eax
imull %edi, %esi
xorl %esi, %eax
ret
I know I am pretty close to write a program which will generate the above mentioned code. But, I am clueless why the script generates different assembly code. Any direction will be helpful.
If you compile your function as is, in optimization level3, -O3 the entire function is optimized out. This is because there is no return value and py and ty are anyways discarded after the function.
For reference the code is below
.globl decod
.def decod; .scl 2; .type 32; .endef
.seh_proc decod
decod:
.seh_endprologue
ret
.seh_endproc
If however, you add a return py; at the end the code generated is as follows.
.globl decod
.def decod; .scl 2; .type 32; .endef
.seh_proc decod
decod:
.seh_endprologue
subl %r8d, %edx
movl %edx, %eax
imull %edx, %ecx
sall $31, %eax
sarl $31, %eax
xorl %ecx, %eax
ret
.seh_endproc
This is functionally identical to what you are expecting.
I'm trying to translate from C to assembly two functions, one that sort an array of index and one that find the minimum number starting from an index. When I run the program it works , the new array is sorted but at the end it gives me this error
1 2 3 3 4 6 7
*** stack smashing detected ***: ./invidia terminated
Annullato (core dump creato)
this is my .c file
#include <stdio.h>
#include <stdlib.h>
int* sort(int* v, int dim);
int min(int v[], int dim, int t);
int main(){
int v[] = {1,3,2,4,6,7,3};
int dim = 7,i;
int *c = sort(v,dim);
for (i = 0; i<dim; i++)
printf("%d ", c[i]);
return 0;
}
/*int* sort(int* v, int dim){
int i,j=0,t;
int mino,temp;
for (t = 0; t<dim; t++){
for(i=t;i<dim;i++){
mino = min (v,dim,t); <- min number from index t
if (v[i]==mino){
temp = v[j];
v[j] = v[i];
v[i] = temp;
j++;
break;
}
}
}
return v;
}
int min(int v[], int dim, int t){
int i, min = 1000;
for (i=t; i<dim;i++)
if (v[i]<min)
min = v[i];
return min;
}
*/
and my .s file
.globl sort
sort: #v->ebx dim-> esi i->edi, j->ecx t->edx, mino->eax, temp ->ebp
pushl %ebx
pushl %esi
pushl %edi
pushl %ebp
subl $32, %esp
movl 52(%esp), %ebx
movl 56(%esp), %esi
movl $0, %edi
movl $0, %ecx
movl $0, %eax
movl $0, %edx
movl $0, %ebp
FOR1:
cmpl %esi, %edx
jge EXIT
movl %edx, %edi
FOR2:
cmpl %esi, %edi
jge EXIT2
movl %ebx, (%esp)
movl %esi, 4(%esp)
movl %edx, 8(%esp)
movl %ebx, 12(%esp)
movl %eax, 16(%esp)
movl %ecx, 20(%esp)
movl %edx, 24(%esp)
call min
movl 12(%esp), %ebx
movl 20(%esp), %ecx
movl 24(%esp), %edx
cmpl (%ebx, %edi, 4), %eax
jne PSEUDOEND
movl (%ebx, %ecx, 4), %ebp
movl %esi, 12(%esp)
movl (%ebx, %edi, 4), %esi
movl %esi, (%ebx, %ecx, 4)
movl %ebp, (%ebx, %edi, 4)
movl 12(%esp), %esi
incl %ecx
incl %edx
jmp FOR1
PSEUDOEND:
incl %edi
jmp FOR2
EXIT:
movl %ebx, %eax
popl %ebp
popl %edi
popl %esi
popl %ebx
addl $32, %esp
ret
EXIT2:
incl %edx
jmp FOR1
.globl min
min:
movl 4(%esp), %ecx
movl 8(%esp), %edx
movl 12(%esp), %ebx
movl $1000, %eax
FOR:
cmpl %edx, %ebx
jge END
cmpl %eax, (%ecx, %ebx, 4)
cmovl (%ecx, %ebx, 4), %eax
incl %ebx
jmp FOR
END:
ret
to compile I use
gcc -m32 filename.c filename.s -o filename
I don't think that the problem is in the assembly translation because it prints correctly the new array. What could be the problem?
Recent times I am having a look at assembly IA32, I did a simple toy example:
#include <stdio.h>
int array[10];
int i = 0;
int sum = 0;
int main(void)
{
for (i = 0; i < 10; i++)
{
array[i] = i;
sum += array[i];
}
printf("SUM = %d\n",sum);
return 0;
}
Yes, I know it is not very recommended to use global variables. I compiled the above code without optimizations and using the flag -s, I got this assembly :
main:
...
movl $0, %eax
subl %eax, %esp
movl $0, i
.L2:
cmpl $9, i
jle .L5
jmp .L3
.L5:
movl i, %edx
movl i, %eax
movl %eax, array(,%edx,4)
movl i, %eax
movl array(,%eax,4), %eax
addl %eax, sum
incl i
jmp .L2
Nothing too fancy and easy to understand, it is a normal while loop. Then I compiled the same code with -O2 and got the following assembly :
main:
...
xorl %eax, %eax
movl $0, i
movl $1, %edx
.p2align 2,,3
.L6:
movl sum, %ecx
addl %eax, %ecx
movl %eax, array-4(,%edx,4)
movl %edx, %eax
incl %edx
cmpl $9, %eax
movl %ecx, sum
movl %eax, i
jle .L6
subl $8, %esp
pushl %ecx
pushl $.LC0
call printf
xorl %eax, %eax
leave
ret
In this case it transformed in a do while type of loop. From the above assembly what I am not understanding is why "movl $1, %edx" and then "movl %eax, array-4(,%edx,4)".
The %edx starts with 1 instead of 0 and then when accessing the array it does -4 from the initial position (4 bytes = integer) . Why not simply ?
movl $0, %edx
...
array (,%edx,4)
instead of starting with 1 if you need to do -4 all the time.
I am using "GCC: (GNU) 3.2.3 20030502 (Red Hat Linux 3.2.3-24)", for educational reasons to generate easily understandable assembly.
I think I finally get the point, I test with:
...
int main(void)
{
for (i = 0; i < 10; i+=2)
{
...
}
}
and got:
movl $2, %edx
and with for (i = 0; i < 10; i +=3) and got :
movl $3, %edx
and finally with (i = 1; i < 10; i +=3) and got:
movl $4, %edx
Therefore, the compiler is initializing %edx = i (initial value of i) + incrementStep;
I have generated two assembly files - one that is optimized, and one that is not. The assembly-language code generated with optimization on should be more efficient than the other assembly-language code. I am more interested in how the efficiency is achieved. To my understanding, in the non-optimized version there will always have to be an offset call to the register %rbp to find the address. In the optimized version, the addresses are being stored in the registers, so you don't have to rely and call on %rbp to find them.
Am I correct? And if so, would there ever be a time when the optimized version will not be advantageous? Thank you for your time.
Here is a function that converts from 42 GIF to CYMK.
void rgb2cmyk(int r, int g, int b, int ret[]) {
int c = 255 - r;
int m = 255 - g;
int y = 255 - b;
int k = (c < m) ? (c < y ? c : y) : (m < y ? m : y);
c -= k; m -= k; y -= k;
ret[0] = c; ret[1] = m; ret[2] = y; ret[3] = k;
}
Here is the assembly-language code that has not been optimized. Note I have made notes using ;; in the code.
No Opt:
.section __TEXT,__text,regular,pure_instructions
.globl _rgb2cmyk
.align 4, 0x90
_rgb2cmyk: ## #rgb2cmyk
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
;;initializing variable c, m, y
movl $255, %eax
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl %edx, -12(%rbp)
movq %rcx, -24(%rbp)
movl %eax, %edx
subl -4(%rbp), %edx
movl %edx, -28(%rbp)
movl %eax, %edx
subl -8(%rbp), %edx
movl %edx, -32(%rbp)
subl -12(%rbp), %eax
movl %eax, -36(%rbp)
movl -28(%rbp), %eax
;;compare
cmpl -32(%rbp), %eax
jge LBB0_5
## BB#1:
movl -28(%rbp), %eax
cmpl -36(%rbp), %eax
jge LBB0_3
## BB#2:
movl -28(%rbp), %eax
movl %eax, -44(%rbp) ## 4-byte Spill
jmp LBB0_4
LBB0_3:
movl -36(%rbp), %eax
movl %eax, -44(%rbp) ## 4-byte Spill
LBB0_4:
movl -44(%rbp), %eax ## 4-byte Reload
movl %eax, -48(%rbp) ## 4-byte Spill
jmp LBB0_9
LBB0_5:
movl -32(%rbp), %eax
cmpl -36(%rbp), %eax
jge LBB0_7
## BB#6:
movl -32(%rbp), %eax
movl %eax, -52(%rbp) ## 4-byte Spill
jmp LBB0_8
LBB0_7:
movl -36(%rbp), %eax
movl %eax, -52(%rbp) ## 4-byte Spill
LBB0_8:
movl -52(%rbp), %eax ## 4-byte Reload
movl %eax, -48(%rbp) ## 4-byte Spill
LBB0_9:
movl -48(%rbp), %eax ## 4-byte Reload
movl %eax, -40(%rbp)
movl -40(%rbp), %eax
movl -28(%rbp), %ecx
subl %eax, %ecx
movl %ecx, -28(%rbp)
movl -40(%rbp), %eax
movl -32(%rbp), %ecx
subl %eax, %ecx
movl %ecx, -32(%rbp)
movl -40(%rbp), %eax
movl -36(%rbp), %ecx
subl %eax, %ecx
movl %ecx, -36(%rbp)
movl -28(%rbp), %eax
movq -24(%rbp), %rdx
movl %eax, (%rdx)
movl -32(%rbp), %eax
movq -24(%rbp), %rdx
movl %eax, 4(%rdx)
movl -36(%rbp), %eax
movq -24(%rbp), %rdx
movl %eax, 8(%rdx)
movl -40(%rbp), %eax
movq -24(%rbp), %rdx
movl %eax, 12(%rdx)
popq %rbp
retq
.cfi_endproc
.subsections_via_symbols
Optimization:
.section __TEXT,__text,regular,pure_instructions
.globl _rgb2cmyk
.align 4, 0x90
_rgb2cmyk: ## #rgb2cmyk
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movl $255, %r8d
movl $255, %eax
subl %edi, %eax
movl $255, %edi
subl %esi, %edi
subl %edx, %r8d
cmpl %edi, %eax ##;; compare m and c
jge LBB0_2
## BB#1: ;; c < m
cmpl %r8d, %eax ## compare y and c
movl %r8d, %edx
cmovlel %eax, %edx
jmp LBB0_3
LBB0_2: ##;; c >= m
cmpl %r8d, %edi ## compare y and m
movl %r8d, %edx
cmovlel %edi, %edx
LBB0_3:
subl %edx, %eax
subl %edx, %edi
subl %edx, %r8d
movl %eax, (%rcx)
movl %edi, 4(%rcx)
movl %r8d, 8(%rcx)
movl %edx, 12(%rcx)
popq %rbp
retq
.cfi_endproc
.subsections_via_symbols
Yes. The optimized version performs many fewer memory read operations by storing intermediate values in registers and not reloading them over and over.
You are using call wrong. It is a technical term that means to push a return address on the stack and branch to a new location for instructions. The term you mean is simply to use the register.
Can you think of a reason that longer, slower code is "better"?