Why I am getting weird output from the following code? [duplicate] - c

This question already has answers here:
Return value from writing an unused parameter when falling off the end of a non-void function
(1 answer)
Checking return value of a function without return statement
(3 answers)
Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?
(1 answer)
Closed 1 year ago.
I think I have found a problem with the way functions are handled by the gcc compiler.
I don't know if it's a mistake or a never distraction on something I've let slip over the years.
In practice, by declaring a function and defining the latter having a return value, the compiler stores the value of the first variable allocated in the range of the function in the EAX register, and then stores it, in turn, within a variable. Example:
#include<stdio.h>
int add(int a, int b)
{
int c = a + b;
;there isn't return
}
int main(void)
{
int res = add(3, 2);
return 0;
}
This is the output:
5
This is the x86-64 Assembly with intel syntax:
Function add:
push rbp
mov rbp, rsp
mov DWORD PTR[rbp-0x14], edi ;store first
mov DWORD PTR[rbp-0x18], esi ;store second
mov edx, DWORD PTR[rbp-0x14]
mov eax, DWORD PTR[rbp-0x18]
add eax, esx
mov DWORD PTR[rbp-0x4], eax
nop
pop rbp
ret
Function main:
push rbp
mov rbp, rsp
sub rsp, 0x10
mov esi, 0x2 ;first parameter
mov edi, 0x3 ;second parameter
call 0x1129 <add>
;WHAT??? eax = a + b, why store it?
mov DWORD PTR[rbp-0x4], eax
mov eax, 0x0
leave
ret
As you can see, it saves me the sum of the parameters a and b in the variable c, but then it saves me in the variable res the eax register containing their sum, as if a function returned values.
Is this done because the function was defined with a return value?

What you've done is trigger undefined behavior by failing to return a value from a function and then attempting to use that return value.
This is documented in section 6.9.1p12 of the C standard:
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
One of the ways that undefined behavior can manifest itself is by the program appearing to work properly, as you've seen. However, there's no guarantee that it will continue to work if for example, you added some unrelated code or compiled with different optimization settings.

eax is the register used to return a value, in this case because it is supposed to return int. So the caller gets whatever happens to be in that registers. However you should have gotten at least a warning, that there is no return statement.
Because your function is pretty small and the compiler decided to use the eax register for it's calculation, it appears to work.
If you switch on optimization or provide a more complex function, the result will be quite different.

Related

Returning a value from a function with no return [duplicate]

This question already has answers here:
Return value from writing an unused parameter when falling off the end of a non-void function
(1 answer)
Checking return value of a function without return statement
(3 answers)
Why does clang produce inefficient asm with -O0 (for this simple floating point sum)?
(1 answer)
Closed 1 year ago.
I think I have found a problem with the way functions are handled by the gcc compiler.
I don't know if it's a mistake or a never distraction on something I've let slip over the years.
In practice, by declaring a function and defining the latter having a return value, the compiler stores the value of the first variable allocated in the range of the function in the EAX register, and then stores it, in turn, within a variable. Example:
#include<stdio.h>
int add(int a, int b)
{
int c = a + b;
;there isn't return
}
int main(void)
{
int res = add(3, 2);
return 0;
}
This is the output:
5
This is the x86-64 Assembly with intel syntax:
Function add:
push rbp
mov rbp, rsp
mov DWORD PTR[rbp-0x14], edi ;store first
mov DWORD PTR[rbp-0x18], esi ;store second
mov edx, DWORD PTR[rbp-0x14]
mov eax, DWORD PTR[rbp-0x18]
add eax, esx
mov DWORD PTR[rbp-0x4], eax
nop
pop rbp
ret
Function main:
push rbp
mov rbp, rsp
sub rsp, 0x10
mov esi, 0x2 ;first parameter
mov edi, 0x3 ;second parameter
call 0x1129 <add>
;WHAT??? eax = a + b, why store it?
mov DWORD PTR[rbp-0x4], eax
mov eax, 0x0
leave
ret
As you can see, it saves me the sum of the parameters a and b in the variable c, but then it saves me in the variable res the eax register containing their sum, as if a function returned values.
Is this done because the function was defined with a return value?
What you've done is trigger undefined behavior by failing to return a value from a function and then attempting to use that return value.
This is documented in section 6.9.1p12 of the C standard:
If the } that terminates a function is reached, and the value of the function call is used by the caller, the behavior is undefined.
One of the ways that undefined behavior can manifest itself is by the program appearing to work properly, as you've seen. However, there's no guarantee that it will continue to work if for example, you added some unrelated code or compiled with different optimization settings.
eax is the register used to return a value, in this case because it is supposed to return int. So the caller gets whatever happens to be in that registers. However you should have gotten at least a warning, that there is no return statement.
Because your function is pretty small and the compiler decided to use the eax register for it's calculation, it appears to work.
If you switch on optimization or provide a more complex function, the result will be quite different.

Does function parameter names has a place in memory in C?

I dont think function parameter names are treated like variables and they doesnt get stored in memory. But I dont get how we can use these parameters in functions as variables if they dont have any place in memory. Can anyone explain me whats going on with function parameters and if they have place or not in memory
All variables are either allocated somewhere or optimized away in case the compiler found them unnecessary. Function parameters are variables and are almost certainly stored either in a CPU register or on the stack, if they are used by the program.
The only time when they might not get allocated is when the function is inlined - when the whole function call is optimized away and the function code is instead injected in the caller-side machine code. In such cases the original variables used by the caller might be used instead.
Function parameter names however are not stored anywhere in the final executable, just like any other identifier isn't stored there either. Names of variables, functions etc only exist in the source code, for the benefit of the programmer alone.
Although your title asks about “function parameter names,” it appears your question is about function parameters, which are different.
Commonly, arguments are passed to functions by putting them in processor registers or on the hardware stack. Each computing platform has some specification of which arguments should be passed where. For example, the first few small arguments (such as int values) may be passed in certain processor registers, while more or larger arguments may be put on the stack.
To the called function, these are parameters. The called function uses them from the processor registers or the stack.
I'm writing this answer assuming you know what the stack and CPU registers are. If you don't, I'd suggest you look them up before seeing this answer.
I dont think function parameter names are treated like variables and they doesnt get stored in memory.
At the assembly level, function parameter names don't really exist. But for function parameters, it depends on the assembly generated based on the compiler's level of optimization. Consider this simple function:
int foo(int a, int b)
{
return a + b;
}
Using Compiler Explorer, I checked the generated disassembly of x64 GCC 10.2. On -O0, it looks like this:
foo:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-8]
add eax, edx
pop rbp
ret
These two lines:
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
interestingly show that the arguments are passed to edi and esi for a and b respectively, and then moved into the stack, presumably in case the registers need to be used elsewhere in the function. The rest of the function uses the space in the stack as opposed to the registers:
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-8]
add eax, edx
(In case you didn't know, eax/rax generally holds the value for functions and edx in this case just serves as a general-purpose register, so these three lines are besaically eax = a; edx = b; eax += edx).
Ok, so that makes sense. The arguments are passed to registers and copied to the stack, where they are used for the rest of the function. What about -O1?
foo:
lea eax, [rdi+rsi]
ret
Now that is a lot shorter. Here, eax gets the value of rdi + rsi and the function ends. All the copying to the stack is completely skipped and the registers are used directly. So yes, in this case, the memory is never used.
EDIT
After writing this answer, I went and checked the generated assembly with the -m32 option and noticed that arguments were always pushed to the stack before the function was called. Assembly generated from -O0 looks like this:
foo:
push ebp
mov ebp, esp
mov edx, DWORD PTR [ebp+8]
mov eax, DWORD PTR [ebp+12]
add eax, edx
pop ebp
ret
Here, since the arguments are passed to the stack before the function is called, they don't have be copied from the registers to the stack (because they're already there). So the function is shorter, and amount of registers used is reduced. However, on higher levels of optimization, the function ends up becoming longer because of this:
foo:
mov eax, DWORD PTR [esp+8]
add eax, DWORD PTR [esp+4]
ret
So with -m32 set, parameters are always placed in memory.

stand alone object code in C and inline functions

I was reading about inline functions from Inline Functions In C when I came across this line:
Sometimes it is necessary for the compiler to emit a stand-alone copy of the object code for a function even though it is an inline function - for instance if it is necessary to take the address of the function, or if it can't be inlined in some particular context, or (perhaps) if optimization has been turned off. (And of course, if you use a compiler that doesn't understand inline, you'll need a stand-alone copy of the object code so that all the calls actually work at all.)
I am completely clueless about what it is trying to say, can somebody please explain it specially what is a stand-alone object code?
"Object code" generally refers to the output from the compiler handed over to the linker, as a middle step before machine code is generated.
What the text says is that if you for some reason take the address of the function, by for example using a function pointer to it, then the function can't be inlined. Because inlined functions don't have an address that can be called upon through a function pointer. Inline functions are just linked in together with the calling code without any function call actually being made.
As you know, an "inline" function is translated to machine-instructions that are "right there." Every time a new "call" to the function appears, those instructions are repeated verbatim in every different place -- the function is not actually "called." (An inline function is very much like an assembler "macro.")
But, if you ask for (say) "the address of" the function, the compiler has to generate a non-inlined copy of it in order to be able to give you one "place where it is."
Here you have an example:
#include <stdio.h>
#include <stdlib.h>
extern inline __attribute__((always_inline)) int mul16(int x) {
return x * 16; }
extern inline __attribute__((always_inline)) int mul3(int x) {
return x * 3; }
int main() {
for(int i = 0; i < 10; i ++)
{
int (*ptr)(int) = rand() & 1 ? mul16 : mul3;
printf("Mul2 = %d", mul16(i));
printf(", ptr(i) = %d\n", ptr(i));
}
}
https://godbolt.org/z/wDpF4j
mul16 exists as a separate object and is also inlined in the same code.
mul16: <----- object
mov eax, edi
sal eax, 4
ret
mul3:
lea eax, [rdi+rdi*2]
ret
.LC0:
.string "Mul2 = %d"
.LC1:
.string ", ptr(i) = %d\n"
main:
push r12
push rbp
push rbx
mov ebx, 0
mov r12d, OFFSET FLAT:mul16
.L5:
call rand
test al, 1
mov ebp, OFFSET FLAT:mul3
cmovne rbp, r12
mov esi, ebx
sal esi, 4 <-------------- inlined version
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov edi, ebx
call rbp
mov esi, eax
mov edi, OFFSET FLAT:.LC1
mov eax, 0
call printf
add ebx, 1
cmp ebx, 10
jne .L5
mov eax, 0
pop rbx
pop rbp
pop r12
ret

Multiplying values in an array using IMUL instruction produces incorrect values

I'm picking up ASM language and trying out the IMUL function on Ubuntu Eclipse C++, but for some reason I just cant seem to get the desired output from my code.
Required:
Multiply the negative elements of an integer array int_array by a specified integer inum
Here's my code for the above:
C code:
#include <stdio.h>
extern void multiply_function();
// Variables
int iaver, inum;
int int_ar[10] = {1,2,3,4,-9,6,7,8,9,10};
int main()
{
inum = 2;
multiply_function();
for(int i=0; i<10; i++){
printf("%d ",int_ar[i]);
}
}
ASM code:
extern int_ar
extern inum
global multiply_function
multiply_function:
enter 0,0
mov ecx, 10
mov eax, inum
multiply_loop:
cmp [int_ar +ecx*4-4], dword 0
jg .ifpositive
mov ebx, [int_ar +ecx*4-4]
imul ebx
cdq
mov [int_ar +ecx*4-4], eax
loop multiply_loop
leave
ret
.ifpositive:
loop multiply_loop
leave
ret
The Problem
For an array of: {1,2,3,4,-9,6,7,8,9,10} and inum, I get the output {1,2,3,4,-1210688460,6,7,8,9,10} which hints at some sort of overflow occurring.
Is there something I'm missing or understood wrong about how the IMUL function in assembly language for x86 works?
Expected Output
The output I expected is {1,2,3,4,-18,6,7,8,9,10}
My Thought Process
My thought process for the above task:
1) Find which array elements in array are negative, for each positive element found, do nothing and continue loop to next element
cmp [int_ar +ecx*4-4], dword 0
jg .ifpositive
.ifpositive:
loop multiply_loop
leave
ret
2) Upon finding the negative element, move its value into register EBX which will serve as SRC in the IMUL SRC function. Then extend register EAX to EAX-EDX where the result is stored in:
mov ebx, [int_ar +ecx*4-4]
imul ebx
cdq
3) Move the result into the negative element of the array by using MOV:
mov [int_ar +ecx*4-4], eax
4) Loop through to the next array element and repeat the above 1)-3)
Reason for Incorrect Values
If we look past the inefficiencies and unneeded code and deal with the real issue it comes down to this instruction:
mov eax, inum
What is inum? You created and initialized a global variable in C called inum with:
int iaver, inum;
[snip]
inum = 2;
inum as a variable is essentially a label to a memory location containing an int (32-bit value). In your assembly code you need to treat inum as a pointer to a value, not the value itself. In your assembly code you need to change:
mov eax, inum
to:
mov eax, [inum]
What your version does is moves the address of inum into EAX. Your code ended up multiplying the address of the variable by the negative numbers in your array. That cause the erroneous values you see. the square brackets around inum tell the assembler you want to treat inum as a memory operand, and that you want to move the 32-bit value at inuminto EAX.
Calling Convention
You appear to be creating a 32-bit program and running it on 32-bit Ubuntu. I can infer the possibility of a 32-bit Linux by the erroneous value of -1210688460 being returned. -1210688460 = 0xB7D65C34 divide by -9 and you get 804A06C. Programs on 32-bit Linux are usually loaded starting at 0x8048000
Whether running on 32-bit Linux or 64-bit Linux, assembly code linked with 32-bit C/C++ programs need to abide by the CDECL calling convention:
cdecl
The cdecl (which stands for C declaration) is a calling convention that originates from the C programming language and is used by many C compilers for the x86 architecture.1 In cdecl, subroutine arguments are passed on the stack. Integer values and memory addresses are returned in the EAX register, floating point values in the ST0 x87 register. Registers EAX, ECX, and EDX are caller-saved, and the rest are callee-saved. The x87 floating point registers ST0 to ST7 must be empty (popped or freed) when calling a new function, and ST1 to ST7 must be empty on exiting a function. ST0 must also be empty when not used for returning a value.
Your code clobbers EAX, EBX, ECX, and EDX. You are free to destroy the contents of EAX, ECX, and EDX but you must preserve EBX. If you don't you can cause problems for the C code calling the function. After you do the enter 0,0 instruction you can push ebx and just before each leave instruction you can do pop ebx
If you were to use -O1, -O2, or -O3 GCC compiler options to enable optimizations your program may not work as expected or crash altogether.

Get returned char from a C function using inline assembly

I have this function that uses inline assembly that basically calls a C function, gets the returned value, and passes that value as a parameter to another function that returns a character.
void convertText(FILE *arch, FILE *result)
{
int i = 0;
int n = arch->size;
_asm {
mov esi, 0
whileS:
cmp esi, n
jge end
mov ebx, result
mov ebx, [ebx]result.information ; Pointer to an array of characters
push esi ; Push parameters to get5bitsFunc
push arch ; Push parameters to get5bitsFunc
call get5bitsFunc
pop arch ; Restore values
pop esi ; Restore values
push eax ; push get5bitsFunc returned value to codify as parameter
call codify
mov edi, eax ; <- HERE move returned value from codify to edi register
pop eax ; restore eax
inc esi
jmp whileS
end:
}
}
Think of codify as function of the type
unsigned char codify(unsigned char parameter) {
unsigned char resp;
// Do something to the parameter
resp = 'b'; // asign value to resp
return resp;
}
I have already tested codify and works fine returning the value I want using C code. The problem is that when I run and debug the convertText code in inline assembly in the line I have marked as "-> Here" the value returned in eax is something of the type 3424242 and not 97 or above in the ascii table that is what I need.
How can I get the char value?
The Windows ABI apparently doesn't require functions returning char to zero- or sign-extend the value into EAX, so you need to assume that the bytes above AL hold garbage. (This is the same as in the x86 and x86-64 System V ABI. See also the x86 tag wiki for ABI/calling convention docs).
You can't assume that zeroing EAX before calling codify() is sufficient. It's free to use all of EAX as a scratch register before returning with the char in AL, but garbage in the rest of EAX.
You actually need to movzx esi, al, (or MOVSX), or mov [mem], al or whatever else you want to do to ignore garbage in the high bytes.
An unsigned char is only 1 byte while eax is a 32-bit (4 byte) register. If codify() is only returning 1 byte, then the return value will be stored in al (the first byte of eax) while leaving the rest of eax untouched (which would result in garbage). I would recommend xor eax, eax before calling codify() so you know that the register is clean before you store the return value in it.

Resources