Reputation: 115
I got this working everyone thank you!
I have a homework to write an assembly program mulq.s that goes with my C program bigmult.c
The C program is supposed to multiply two unsigned hexadecimal numbers together. I got it started but I think I need a lot of help. This is an introduction to assembly so it's not very long.
Here is the full question:
You are to write a C program called big_mult.c that multiplies two unsigned integers, x and y, read from the command line. The output is a pair of unsigned integers representing the most significant and least significant 64 bits of the full 128-bit product x * y. The inputs and outputs are to be given in hexadecimal format. Your C program will take care of reading the inputs and printing the output, but it will call a function mull.s to do the actual multiplication. Your C program should use only int or unsigned int variables and should not do any arithmetic. The function defined by mull.s should have the following declaration in C before the procedure main. void mull(unsigned int x, unsigned int y, unsigned int* high, unsigned int* low); The least significant 64 bits of the product are to be assigned to low, and the most significant 64 bits of the product are to be assigned to high. Remember to put an appropriate header comment into your assembly file (the ordinary C comment /* ... */ will work for assembly too). One way to approach writing this assembly program is to write a similar program in C, compile it to assembly code using the -S option, and modify the resulting assembly code to do what you need. Your final assembly code should be very short and should contain only one multiplication instruction mull.
I started writing a dummy program to get the unimportant parts of the code at the top and then I'm completely lost on what to do. I have pushq instruction to push %rbp and move the address to %rsp. What am I supposed to do after this?
Any hints would be welcome!
My code so far:
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main:
pushq %rbp
movq %rsp, %rbp
My C program:
#include <stdio.h>
void mull(unsigned int x, unsigned int y, unsigned int* high, unsigned int* low);
int main(int argc, char* argv[]) {
unsigned long long int x, y;
if(argc != 3)
printf("Usage: bigmult x1 x2 <where x1 and x2 are hexadecimal integers>\n");
else {
sscanf(argv[1], "%x", &x);
sscanf(argv[2], "%x", &y);
printf("%x x %x = ", x, y);
mull(x, y, &x, &y);
}
return 0;
}
Upvotes: 0
Views: 1280
Reputation: 7873
I would love to add my own comment but the !#*&$% stackoverflow rules prohibit me from commenting until I have 28 million cred points (perhaps a bit fewer).
First of all, you want to write your mull() function in C just as simply as possible. The resulting code will be simpler (MUCH simpler) if you use as inputs two 32-bit integers (probably just 'int', but depends on your platform). If you do that, judging from your professor's comments, that should boil down to a single multiply instruction that does 32bit*32bit=64bit multiplication. If you use 64-bit integers as your inputs, there may not be a 64bit*64bit=128bit instruction on your CPU, but even if there is it's overkill for your assignment. If there isn't, then the compiler will emit a sequence of instructions to perform the 64bit*64bit=128bit multiplication, making it oh-so-much-harder for you to understand what's going on.
When you get your separate C file building to an object file & linking with main()'s object file, what you want to do then is get its disassembly & look for the multiply instruction. Once you've found it, track backwards to find out where its arguments came from... they may be in registers or perhaps memory locations on the stack, depending on your system's ABI. Then trace forwards until the function's return to see where the results of the multiplication go when it's returned to the caller.
You will want to duplicate that functionality in your assembly version of mult(), but with this exception: The C-code compiled version probably includes a good bit of prologue and epilogue instructions that simply aren't needed in a function that's as simple as mult(). But unless the compiler is really really good at optimizing, it won't notice that and the compiled result will be probably eight times as long as it really needs to be. From your professor's comments, your entire mult() assemly function might even be as short as 2 to 6 instruction total... and depending on your ABI, you may or may not even need to use the stack. (For x86, you will, but for PowerPC or other RISC machines you wouldn't need to for such a simple function since for many RISC machines, functions with just a few args get all their args passed in registers so they don't need the stack at all.)
So, assuming you DO need to use the stack, your function might look something like this:
_mult:
...instructions to move parameters from stack locations into registers...
...multiply instruction using those registers...
...instructions to move the results into the appropriate stack locations
for return values (or return value registers, depending on your ABI)...
...and finally, your processor's "return" instruction
...for a total of perhaps 6 instructions maximum.
Upvotes: 2