When I run my program with the -m32 flag, I receive a segmentation fault error when trying to print out the values of 2 Floating point objects (MyFloat
)—I am trying to model a floating point number from scratch using the MyFloat
class.
The strange thing is that when I open up the debugger, the 2 MyFloat objects have all the correct properties in them and have implemented the overloading of the <<
operator, yet printing them out produces a segmentation fault (the segmentation fault occurs at line):
cout << "Usage: " << argv[0] << " float_a +/- float_b" << endl;
Looking at the debugger, I can see the actual values in mf1 and mf2:
$1 = {_vptr.MyFloat = 0x56558e90 <vtable for MyFloat+8>, sign = 0,
exponent = 130, mantissa = 2097152}
$1 = {_vptr.MyFloat = 0x56558e90 <vtable for MyFloat+8>, sign = 0,
exponent = 130, mantissa = 2097152}
If I do not use the -m32 flag, everything is printed out fine. Below is my Class header, Class implementation, and main.cpp code.
MyFloat.h:
/*
* MyFloat.h
*
* Created on: Dec 7, 2020
* Author: ubuntu
*/
#ifndef MYFLOAT_H_
#define MYFLOAT_H_
#include <iostream>
using namespace std;
class MyFloat {
public:
//constructors
MyFloat();
MyFloat(float f);
MyFloat(const MyFloat & rhs);
virtual~MyFloat() {};
//output
friend ostream & operator << (std::ostream & strm, const MyFloat & f);
//addition
MyFloat operator+(const MyFloat & rhs) const;
//subtraction
MyFloat operator-(const MyFloat & rhs) const;
//comparison
bool operator==(const float rhs) const;
private:
unsigned int sign;
unsigned int exponent;
unsigned int mantissa;
void unpackFloat(float f);
float packFloat() const;;
};
#endif /* MYFLOAT_H_ */
MyFloat.cpp:
/*
* MyFloat.cpp
*
* Created on: Dec 7, 2020
* Author: ubuntu
*/
#include "MyFloat.h"
#include "MyFloat.h"
/*
* The bitset library is used to debug this program: printing out the binary representation
* of integers.
*/
#include <bitset>
#include <stdio.h>
#include <string.h>
MyFloat::MyFloat(){
sign = 0;
exponent = 0;
mantissa = 0;
}
MyFloat::MyFloat(float f){
unpackFloat(f);
}
MyFloat::MyFloat(const MyFloat & rhs){
sign = rhs.sign;
exponent = rhs.exponent;
mantissa = rhs.mantissa;
}
ostream& operator<<(std::ostream &strm, const MyFloat &f){
//this function is complete. No need to modify it.
strm << f.packFloat();
return strm;
}
void MyFloat::unpackFloat(float f) {
//this function must be written in inline assembly
//extracts the fields of f into sign, exponent, and mantissa
__asm__(
"movl %%eax, %%ebx;" // Load the floating point number into the sign register
"shr $31, %%ebx;" // Shift the sign bit to the end
// Load in the bitmasks into the EDI and ESI registers
"movl $0x7f800000, %%edi;" // Bitmask to retrieve the exponent
"movl $0x7fffff, %%esi;" // Bitmask to retrieve the mantissa
"movl %%eax, %%ecx;" // Load the floating point number into the exponent register
"andl %%edi, %%ecx;" // Cancel all the bits except the mantissa bits
"shr $23, %%ecx;" // Shift the mantissa bits to the end
"movl %%eax, %%edx;" // Load the floating point number into the mantissa register
"andl %%esi, %%edx;" // Cancel all the bits except the mantissa bits
// We do not need to shift the mantissa to the end (since it is
// already at the end)
// Load the floating pointer
: "=b" (sign), "=c" (exponent), "=d" (mantissa)
: "a" (f)
: "cc"
);
}//unpackFloat
float MyFloat::packFloat() const{
//this function must be written in inline assembly
//returns the floating point number represented by this
unsigned int f;
float f2;
__asm__(
// Load the sign bit into the floating point number
"movl %%ebx, %%eax;"
// Move the sign bit from the LSB to the MSB
"shl $31, %%eax;"
// Generate the bitmask for loading in the mantissa (EDI register)
"movl %%ecx, %%edi;"
// Right now, the mantissa bits are aligned at the end. We want to move them
// to their proper position (bits 2-9)
"shl $23, %%edi;"
// Load the mantissa into the floating point number
"orl %%edi, %%eax;"
// Generate the bitmask for loading in the exponent (ESI register)
"movl %%edx, %%esi;"
// Load the exponent into the floating point number
"orl %%esi, %%eax;"
// Load the floating pointer
: "= a" (f)
: "b" (sign), "c" (exponent), "d" (mantissa)
: "cc", "%edi", "%esi"
);
memcpy(&f2, &f, sizeof(f));
return f2;
}//packFloat
//
main.cpp:
#include <cstdlib>
#include <iostream>
#include "MyFloat.h"
using namespace std;
int main(int argc, char ** argv) {
float f1, f2;
//float fres;
MyFloat mfres;
cout.precision(1000);
if (argc != 4) {
cout << "Usage: " << argv[0] << " float_a +/- float_b" << endl;
} else {
f1 = strtof(argv[1], NULL);
f2 = strtof(argv[3], NULL);
MyFloat mf1(f1);
MyFloat mf2(f2);
cout << mf1 << ' ' << argv[2][0] << ' ' << mf2 << endl;
//cout << "I did it = " << boolalpha << (mfres == fres) << endl;
}
return 0;
}
Note that I am also compiling with the -std=c++11 flag.