I am making an os and have booted into a 64 bit kernel made in c. I have made a print function which is working and am trying to make a function to convert hex values to string so I can print them. My code is causing boot loops, yet when I compile the exact same code to run normally in linux it works perfectly. The relevant code:
int logarithm(double value, int base, int* output) {
int i = 0;
while (value > 1) {
value /= base;
i ;
}
*output = i;
}
int power(int value, int power, int* output) {
if (power == 0) {
value = 1;
} else {
for (int i = 0; i < (power - 1); i ) {
value *= value;
}
}
*output = value;
}
void hexToStr(unsigned int hex, char** string) {
int hexLength = 0;
logarithm((double)hex, 16, &hexLength);
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i ) {
power(16, i, &powerValue);
output[hexLength - i - 1] = (hex & (powerValue * 15)) / powerValue '0';
}
*string = output;
}
If I change the hexToStr() function code to this (removing the need for logarithm() and power() functions by hardcoding values for the string), it works in both linux and my kernel:
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i ) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
Any suggestions as to why this would happen?
CodePudding user response:
The presented code invokes undefined behavior. For example let's consider this function
void hexToStr(unsigned int hex, char** string) {
int hexLength = 10;
char output[hexLength];
output[hexLength] = 0;
int powerValue = 0;
for (int i = 0; i < hexLength; i ) {
output[hexLength - i - 1] = 'A';
}
*string = output;
}
In this assignment statement:
output[hexLength] = 0;
there is written data outside the array because the valid range of indices is [0, hexLength)
.
Or the function sets a pointer passed to the function by reference to the local array output
that will not be alive after exiting the function. So the returned pointer will have an invalid value.
Another example the result value of the function power
when the parameter value
is equal to 3
and the parameter power
is equal to 3
will be equal to 81
instead of 27
due to the assignment statement in this for loop.
for (int i = 0; i < (power - 1); i ) {
value *= value;
}
Moreover the function returns nothing though its return type is not void.
int power(int value, int power, int* output) {
Also this expression
(hex & (powerValue * 15)) / powerValue '0'
does not make a sense.
CodePudding user response:
Needed to enable SSE unit to work with floats and doubles. As well as change how values are passed back. Working code:
void log(float value, float base, uint64_t* output) {
uint64_t i = 0;
while (value >= 1) {
value /= base;
i ;
}
*output = i;
}
void pow(uint64_t value, uint64_t exponent, uint64_t* output) {
uint64_t result = 1;
for (uint64_t i = 0; i < exponent; i ) {
result = result * value;
}
*output = result;
}
void hexToStr(uint64_t hex, char* output) {
uint8_t hexLen = 16;
log((float)hex, (float)16, &hexLen);
char result[hexLen 3];
result[0] = '0';
result[1] = 'x';
result[hexLen 2] = 0;
uint64_t powerValue = 1;
for (uint8_t i = 0; i < hexLen; i ) {
pow(16, i, &powerValue);
result[hexLen - i 1] = (hex & (uint64_t)(powerValue * (uint64_t)15)) / powerValue '0';
}
for (uint8_t i = 0; i < hexLen 3; i ) {
switch(result[i]) {
case ':':
result[i] = 'A';
break;
case ';':
result[i] = 'B';
break;
case '<':
result[i] = 'C';
break;
case '=':
result[i] = 'D';
break;
case '>':
result[i] = 'E';
break;
case '?':
result[i] = 'F';
break;
}
output[i] = result[i];
}
}