I am writing mips code in MARS that uses system call code 5 to read an integer.
Is there a way to verify that the integer input is within the 32-bit range?
If you allow both positive and negative integers, there is no way to verify that the integer input is within the 32-bit range, since the MARS syscall does not appear to return any error status.
Related
Checking MIPS algorithm overflow
error: .assciiz "error: the input number is two big."
buffer: .space 256
For QtSpim, using syscall #5, input integer, there appears to be no way to detect when user input exceeds the 32-bit signed integer range. No success/failure error code is returned, and the value returned by the syscall, given whatever the user entered, is simply truncated to 32 bits1.
If you want to do overflow checking, you'll have accept string data (instead of integer data) from the console and parse the string to integer checking for overflow during that parse.
Such a parse involves doing a multiplication by 10 and an addition for each digit, so with one approach both of those arithmetic operations would need to involve overflow checking.
Importantly, the input to the parse would be a string, and the output would both a status and a numeric value, unlike syscall #5, so your program can customize behavior. The status could indicate success, or failures of various kinds, such as non-digit characters, and overflow.
Other approaches to determining the overflow during parse of string to integer are possible, since we know certain facts about decimal digits, such as at most 9 will be added each digit; since we know that 11 total digits (or more) it will overflow (not counting leading zeros, if present).
For example, an alternative approach is to compute the intermediate parse result in 64-bits, then only when converting to 32 bits, check for match of the 32-bit value with the original 64-bit value (match is ok, non-match is overflow). Since 64 bits can still overflow, counting of total non-zero digits should also be employed with this approach, where anything over 11 would indicate overflow.
The other popular MIPS simulator MARS presents a different challenge/opportunity on overflow with syscall #5 — it takes an exception on overflow, but this is not like a Java or C# exception that is easily caught and handled, but instead this is a fault that transfers control to the kernel exception handler in supervisor mode.
Doing something useful with that would be a topic of advanced operation system coursework. For one, once you write your own kernel exception handler, you have to be prepared to handle all possible processor exceptions, not just overflow; for another you have to differentiate between the overflow condition and the others so you can handle them separately; and lastly, there's no predefined interface for telling the overflowing user-mode program using syscall #5, that this has occurred, and what the user-mode program wants to do about it, so you'd have to provide such mechanism.
1 These simulators implement effectively useful but an irregular set of system calls — there appears no attempt made to make a complete or well rounded set of syscall operations. For example, you can read or print an integer or string from/to the console, but can only read or print strings from files — if you want to use files instead of the console with integers, now you have to write your own int to string and vice versa.
I am working with the mips assembly language but am confused on the overflow aspect of arithmetic here.
Say I am subtracting 25 from 20 and end up with -5. Would this result in an overflow?
I understand that with addition if you add 2 positive numbers or 2 negative numbers and the output is the opposite sign then there is overflow but am lost when it comes to subtraction.
Find the examples at the extreme, let's do it in 8 bits signed to make it simple but the same principles holds in 32 bits
minuend: the smallest possible positive (non-negative) number, 0 and
subtrahend: the largest possible number, 127
When we do 0 - 127, the answer is -127 and that indeed fits in 8 bits signed. There is a borrow. In any processor the effect of the borrow is to propagate 1's though out the upper bits, making it a negative number of the proper magnitude.
Different processors set flags differently based on this borrow, MIPS doesn't have flags, while x86 will set flags to indicate borrow, and other processors will set the flags to indicate carry.
In 8 bit signed numbers:
minuend: the smallest possible positive (non-negative) number, 0 and
subtrahend: the largest possible number, -128
When we do 0 - -128, the answer should be 128, but that cannot be represented in 8 bit signed format, so this is the example of overflow. 0 - -127 = 127 and that can be represented, so no overflow there.
If we do it in 8 bits unsigned, your example of 25-20 = -5, but -5 cannot be represented in an unsigned format, so this is indeed overflow (or modular arithmetic, if you like that).
Short answer: Yes, as the 32-bit representation of -5 is FFFFFFFB.
Long answer: Depends on what you mean by "overflow".
There's signed overflow, which is when you cross the 7FFFFFFF-80000000 boundary.
And there's unsigned overflow where you cross the FFFFFFFF-00000000 boundary.
For signed arithmetic, signed overflow is undeniably a bad thing (and is considered undefined behavior in C and other languages). However, unsigned overflow is not necessarily a problem. Usually it is, but many procedures rely on it to work.
For example, imagine you have a "frame timer" variable, i.e. a 32-bit counter variable that increments by 1 during an interrupt service routine. This interrupt is tied to a real-time clock running at 60 hertz, so every 1/60th of a second the variable's value increases by 1.
Now, this variable will overflow eventually. But do we really care? No. It just wraps around back to zero again. For our purposes, it's fine, since we really don't need to know that accurately how long our program has been running since it began. We probably have events that occur every n ticks of the timer, but we can just use a bitmask for that. Effectively in this case we're using unsigned overflow to say "if this value equals FFFFFFFF and we're about to add 1 to it, reset it to zero instead." Which thanks to overflow we can easily implement without any additional condition checking.
The reason I bring this up is so that you understand that overflow is not always a bad thing, if it's the unsigned variety. It depends entirely on what your data is intended to represent (which is something you can't explain even to a C compiler.)
I was trying to reverse engineer some psp programs developed using the free
pspsdk
https://sourceforge.net/projects/minpspw/
I noticed that i created a function to see how MIPS handles more than 4 arguments (a0-a4).
Everyone i know has told me that they get passed onto the stack.
To my surprise, that 5th argument was actually passed to register t0 and to compiler didn't even use the stack!
it also inlined a function without even having used a jal or jump to it. (obvious optimization).
Altough there was indeed a space a memory and you could double check by using print with function pointer argument. That actual code that was executed was automatically inlined without the need of a function call instruction.
^^ but that doesn't really benefit me for a reverse engineer attempt...
there is a man page for this version of gcc. and it takes seconds to install if anyone is able to provide it's man for compilation if there is one.
It's so long i don't even know how to reference information reliably
How arguments are passed is specified by the ABI (application binary interface). So you have to find respective documents.
Moreover, there is more than one such ABI, namely n32 and n64. In the case of mips-gcc, some of the decisions are commented in the GCC sources like in ./gcc/config/mips/mips.h
/* This structure has to cope with two different argument allocation
schemes. Most MIPS ABIs view the arguments as a structure, of which
the first N words go in registers and the rest go on the stack. If I
< N, the Ith word might go in Ith integer argument register or in a
floating-point register. For these ABIs, we only need to remember
the offset of the current argument into the structure.
The EABI instead allocates the integer and floating-point arguments
separately. The first N words of FP arguments go in FP registers,
the rest go on the stack. Likewise, the first N words of the other
arguments go in integer registers, and the rest go on the stack. We
need to maintain three counts: the number of integer registers used,
the number of floating-point registers used, and the number of words
passed on the stack.
We could keep separate information for the two ABIs (a word count for
the standard ABIs, and three separate counts for the EABI). But it
seems simpler to view the standard ABIs as forms of EABI that do not
allocate floating-point registers.
So for the standard ABIs, the first N words are allocated to integer
registers, and mips_function_arg decides on an argument-by-argument
basis whether that argument should really go in an integer register,
or in a floating-point one. */
There are more such comments in the mips backend. Search for "cumulative" or "CUMULATIVE" in mips.c and mips.h.
So I've seen a lot of questions on generating random integers in a MIPS program using MARS and syscall 42 and that's ok. The problem is that I need to generate a random integer for a program compiled with QtSpim, which has no syscall for 42 or however for calls greater than 17.
I can't figure out getting something like a random value from the system like syscall 30 in MARS which gives the system time.
Is there a way to get a random address or hex value to use for a random int generator using xor operations ?
Any help would be appreciated.
Everyone knows about overflow in the programming languages, if it happens program goes to crash. However, it is not clear for me what happens actually with data which get out of the boundary. Could you explain me, saying, giving example on C++ or Java. For example, Integer can save maximum 4 byte, what will happen if one puts data more than 4 byte to Integer. How compiler will identify this undefined behaviour?
what will happen if one puts data more than 4 byte to Integer.
Typically the value will roll-over1, meaning it will jump from one end of its range to another.
This can be seen, even in Windows calculator. Start with the highest possible signed 32-bit value:
Now add one to it:
We overflowed the maximum value of a signed Dword (231-1).
1 - This is a typical result. Some architectures might actually generate an exception on integer overflow, so you shouldn't count on this behavior.
How compiler will identify this undefined behaviour?
The compiler won't identify it. That's the problem. C# can mitigate this with the checked keyword, which checks to make sure that any arithmetic done on an integer will not cause overflow/underflow.