GIDForums  

Go Back   GIDForums > Computer Programming Forums > Assembly Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 22-Apr-2008, 12:35
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about
Exclamation

Mixing C and assembly in x86 - Makefile nuances


hello,

I have been trying to write a C program and call an assembly routine from within the C program.
Im following the C calling convention.

I have written the following assembly routine and named the file 'mul64_32.asm' and this file is as shown below, I have a routine which is called 'llmultiply' which I call from the C source file. In this assembly routine, I assume that the stack looks like as shown in the second ASCII art figure here.
Code:
SECTION .data SECTION .text ; stuff below goes into the TEXT segment of the processor ALIGN 16 ; align segments on a 16-byte boundary BITS 32 ; generate code for 32 bits processor GLOBAL _llmultiply ; llmultiply will be used somewhere else(in our case a C file and in tht fil it'll be defined EXTERN _llmultiply ;; subroutine prologue push ebp ;save old pts value mov ebp,esp ;set the new base ptr value ;; saving the registers to be modified in the code push eax push ecx push edx push edi push esi ;; start the subroutine mov eax,[ebp+8] ; get Al mov ebx,[ebp+16] ; get Bl..so ebx is NOT a pointer to Bl...it directly has the value..since we've used square brackets around ebp+16! mul ebx ; multiply Bl with Al. EDX:EAX = upper(Al*Bl):lower(Al*Bl) mov edi,eax ; store lower 32 bits of Al*Bl into edi mov esi,edx ; store upper 32 bits of Al*Bl into esi mov eax, [ebp+12] ; get Ah mul ebx ; multiply Bl with Ah, EDX:EAX upper(Bl*Ah):lower(Bl*Ah) add eax,esi ; Add upper(Al*Bl) with lower(Bl*Ah) adc edx,0 ; now edx contains the carry out from the previous addition plus upper(Bl*Ah) mov esi,eax ; mov lower32 of above addition to esi mov ecx,edx ; mov upper(Bl*Ah) and carry from above add to ecx mov eax, [ebp+20] ; get Bh mov ebx, [ebp+8] ; get Al mul ebx ; multiply Bh * Al, EDX:EAX upper(Bh*Al):lower(Bh*Al) add eax,esi ; add lower(Bh*Al) with upper(Al*Bl) and lower(Bl*Ah) adc edx,ecx ; add upper(Bh*Al) with the carry(from above addition) mov esi,eax ; lower word of partial product goes into esi mov ecx,edx ; higher word of partial product goes into ecx mov eax, [ebp+12] ; get Ah mov ebx, [ebp+20] ; get Bh mul ebx ; multiply Bh * Ah, EDX:EAX upper(Bh*Ah):lower(Bh*Ah) add eax,ecx ; add higher word of partial product with lower word of Ah*Bh. result in eax adc edx,0 ; add carry from previous addition with higher word of Ah*Bh and result in EDX ;; now our product looks like edx:eax:esi:edi and we need to somehow get {[ebp + 24] to [ebp + 28]} to show us the location of the result ;; now [ebp+27] is only an eight bit data. what happens when I transfer it to ebx?..what abt the remaining 24bits? Im assuming they get filled with zeros automatically. mov ebx, 0x00000000 ; clear register ebx add ebx,[ebp+27] ; now ebx contains the MSB of start address of result, so basically ebx is like a ptr tp ptr in C shl ebx,24 ; shift the MSB to the 'right' location in the register mov ecx, 0x00000000 ; clear register ecx add ecx,[ebp+26] ; get the next MSB into ecx shl ecx,16 ; shift the MSB to the corresponding location in the reg add ebx,ecx ; Now ebx contains the upper word of the start address mov ecx, 0x00000000 ; clear register ecx add ecx,[ebp+25] ; get the next MSB into ecx shl ecx,8 ; shift the MSB to the corresponding location in the reg add ebx,ecx ; Now ebx contains the upper 24bits of the start address at the proper bit locations mov ecx, 0x00000000 ; clear register ecx add ecx,[ebp+24] ; get the LSB into ecx add ebx,ecx ; Now ebx contains the proper start address of 'result' ;; now we move the various 32bit wide chunks of the result into the actual 'result' variable mov [ebx],edi ; lower 32bits of the result start from result(0) mov [ebx + 8],esi ; next 32bits of the result start from result(8) mov [ebx + 16],eax ; next 32bits of the result start from result(16) mov [ebx + 24],edx ; final 32bits of the result start from result(24) ;; subroutine epilogue -- now we pop the values out in the reverse order and restore the state of the machine pop esi pop edi pop edx pop ecx pop eax pop ebp ret

In this program Im trying to implement a 64*64 multiplication using 32bit registers present in an x86 platform. Now this is exactly what Im trying to do but everything in C in this thread wherein I had segfault issues which were pointed put by dave. That code is still buggy but since my labs require me to hand in the assembly one first, im stuck with this!

Now I call this from the following C file which is called 'main.c'.
CPP / C++ / C Code:
#include "libepc.h"
#include <stdlib.h>

extern void llmultiply(QWORD64 l1, QWORD64 l2, unsigned char *result);

int main()
{
    int crsr_cnt = 0;
    unsigned char result[16];//array to store the result of the multiplication

    QWORD64 L1;
    QWORD64 L2;

    L1 = 0x12FF353C;
    L2 = 0x5A2F12AF;

    ClearScreen(0x07);
    SetCursorPosition(crsr_cnt++, 0);

    llmultiply(L1,L2,result);//call assembly routine with the needed args, compiler takes care of passing params and ret val
    PutString("the result is\n");

    SetCursorPosition(crsr_cnt++, 0);
    PutUnsigned(*result,16,16);

    return 0;
}
Im using the NASM assembler on a windows workstation at school and I have done the setup according to these directions. But I do not understand how do I use the make file shown below to get the C file see the assembly routine in another '.asm' file. I have my asm source file in the same directory as the C source file but djpp(a windows port of gnu c compiler) complains that it cannot find the function 'llmultiply' which is defined in the asm file. Should I include the asm file in a header and include the header instead? By the way heres the Makefile and Makefile.common

Makefile
Code:
OBJ = main.o FLOPPY = floppy.img include Makefile.common
Makefile.common:
Code:
LDSCRIPT = Z:\workspace\link.cmd BOOTSECT = Z:\workspace\bootload.bin COPYDISK = Z:\workspace\copydisk.exe INCLUDES = -I "c:\program files\virtutech\simics-3.0.9\extras\libepc" $(EXTRA_INCLUDES) CC = gcc CFLAGS = -Wall -pedantic -W $(INCLUDES) LD = ld LDFLAGS = -T$(LDSCRIPT) -ustart -Map link.map AS = nasm ASFLAGS = -f coff all: embedded.bin $(COPYDISK) -b $(BOOTSECT) -o $(FLOPPY) embedded.bin embedded.bin: $(OBJ) $(LD) $(OBJ) $(LIBS) $(LDFLAGS) %.o: %.c $(CC) $(CFLAGS) -c $< %.o: %.asm $(AS) $(ASFLAGS) $< clean: del *.o *.bin *~
And when I run 'make' from the directory where the Makefile is I get the following errors:
Code:
make -k all gcc -Wall -pedantic -W -I "c:\program files\virtutech\simics-3.0.9\extras\libepc" -c main.c In file included from main.c:1: c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:26: warning: ANSI C does not support `long long' c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:28: warning: ANSI C does not support `long long' c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:192: warning: ANSI C forbids zero-size array `bfr' ld main.o -TZ:\workspace\link.cmd -ustart -Map link.map main.o(.text+0x72):main.c: undefined reference to `_llmultiply' make: *** [embedded.bin] Error 1 make: Target `all' not remade because of errors.
Now this is really bugging me since I cannot even test to see if at all my code even works.
Hope to hear from you guys,
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #2  
Old 22-Apr-2008, 13:16
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,311
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Mixing C and assembly in x86 - Makefile nuances


Quote:
Originally Posted by aijazbaig1
I have been trying to write a C program and call an assembly routine from within the C program.
I have written the following assembly routine and named the file 'mul64_32.asm' ...
I have no way of testing, but it seems to me that the rule in Makefile.common will create mul64_32.o from mul64_32.asm by invoking the assembler. Namely by executing the following command
Code:
nasm -f coff mul64_32.asm

What happens when you execute that from a command line?

If it does create mul64_32.o, then look at the Makefile:

Makefile
Code:
OBJ = main.o FLOPPY = floppy.img include Makefile.common

You have to tell the make program that the target depends on mul64_32.o also.

Maybe try changing the Makefile to
Code:
OBJ = main.o mul64_32.o FLOPPY = floppy.img include Makefile.common

Then try
Code:
make clean make

Just a guess.

Regards,

Dave
  #3  
Old 23-Apr-2008, 06:13
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 156
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about

Re: Mixing C and assembly in x86 - Makefile nuances


Well...the technique you told above did work for me. I did change the Makefile as you suggested and then I tried building the binary and the floppy image by executing the 'make' command after I manually assembled the assembly code.

But as with the latter part of this thread, the result was all zeros.

As our school workstation do not have gdb installed on their windows workstations (they have it on limux and solaris, i dunno why not on windows.. ), I have reverted to having lots of printfs sprinkled in my asm code. So now I had to figure out ways to include C functions in assembly. So after referring to class notes and various resources over the web, I came up with something like this:

Now my make file is:
Code:
OBJ = main.o mul64_32.o FLOPPY = floppy.img include Makefile.common
'Makefile.common' is still the same as the previous post

Addionally 'main.c' is exactly the same as above.

Shown below is what I have added to the asm file so I could call the C printf function from within it. And as you've guessed it doesn't work.
Code:
; | ; |same as the code in my post above--shown below is the added part : | format_text: db 'the value of register ebx is \"0x%lX\" \n', 10, 0 _llmultiply ;; subroutine prologue push ebp ;save old pts value mov ebp,esp ;set the new base ptr value ;; saving the registers to be modified in the code push eax push ecx push edx push edi push esi ;; start the subroutine mov eax,[ebp+8] ; get Al mov ebx,[ebp+16] ;; now we check if we have the proper values push ebx ; push the 2nd arg to printf push dword format_text ; push the 1st arg to printf call _printf ; call the C printf func ;; now we pop out the arguments to printf and restore the stack pop ebx pop format_text ; <-- ERROR HERE
Now I guess I have got the syntax wrong or something. I do a 'make clean' followed by plain 'make -k all'.

I dunno what that 'k' is for there but we have been advised to use eclipse which I sometimes do and sometimes don't and when I issue the 'clean project' command from eclipse, it automatically inserts the 'k' in there.
Anyways..point is...even if theres a 'k' or not...I haven't got the "_printf" part right.
This is what the compiler complains about:
Code:
gcc -Wall -pedantic -W -I "c:\program files\virtutech\simics-3.0.9\extras\libepc" -c main.c In file included from main.c:1: c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:26: warning: ANSI C does not support `long long' c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:28: warning: ANSI C does not support `long long' c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:192: warning: ANSI C forbids zero-size array `bfr' nasm -f coff mul64_32.asm mul64_32.asm:37: invalid combination of opcode and operands make: *** [mul64_32.o] Error 1
So what could I do now!
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
  #4  
Old 23-Apr-2008, 08:29
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 5,311
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Mixing C and assembly in x86 - Makefile nuances


Quote:
Originally Posted by aijazbaig1
c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:26: warning: ANSI C does not support `long long'
c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:28: warning: ANSI C does not support `long long'
To get rid of this warning, change the CFLAGS definition in Makefile.common to
Code:
CFLAGS = -Wall -pedantic -W -std=c99 $(INCLUDES)
Quote:
Originally Posted by aijazbaig1
c:/program files/virtutech/simics-3.0.9/extras/libepc/libepc.h:192: warning: ANSI C forbids zero-size array `bfr'
Since you haven't shared with us the contents of libepc.h, how could we guess?
Quote:
Originally Posted by aijazbaig1
nasm -f coff mul64_32.asm
mul64_32.asm:37: invalid combination of opcode and operands
make: *** [mul64_32.o] Error 1[/code]
I have no idea of the opcodes, operations, and syntax of nasm. I am guessing that it only works with registers. (What the heck would you be popping here, and with what effect, even if it were allowed?)

I observe that C compilers typically clean up the stack after calling a function by adding to a number (equal to the lengths of all of the arguments that were pushed) to the stack pointer, not by using multiple pop instructions.

Note that if you need to restore the old value of ebx (I don't know whether it is necessary), you have to pop the stuff in reverse order.

maybe:

Code:
push ebx ; push the 2nd arg to printf push dword format_text ; push the 1st arg to printf call _printf add ebp,4 ;clean up the stack from the format_text pointer pop ebx ; restore ebx, just in case...

If you know that the called function doesn't screw with ebx (or if you don't need to restore its value, then instead of add, pop you could just add ebp,8

Disclaimer: I have no way of testing. Furthermore, this pretty much exhausts my knowledge of and enthusiasm for the subject. Maybe some other assembly language wonk can contribute some suggestions.


Regards,

Dave
 
 

Recent GIDBlogInstall Adobe Flash - Without Administrator Rights by LocalTech

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
C mixed with assembly x86 ChristieGiorgos Assembly Language 1 23-Mar-2008 06:47
Standard Assembly Languages Peter_APIIT Assembly Language 10 23-Mar-2008 06:31
Hangman in Assembly zeliie Assembly Language 1 24-Nov-2007 11:32
Assemblers & assembly language BlueFireCO. Assembly Language 2 26-Mar-2007 09:56

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 12:23.


vBulletin, Copyright © 2000 - 2010, Jelsoft Enterprises Ltd.