This question already has answers here:
Compiler generates costly MOVZX instruction
(2 answers)
Why doesn't GCC use partial registers?
(3 answers)
Closed 1 year ago.
I have following snippet:
typedef struct {
unsigned int gender: 1;
unsigned int age: 7;
unsigned int uid: 24;
} person;
int
f(person *p) {
return p->gender;
}
which generates (gcc -O2):
f:
movzx eax, BYTE PTR [rdi] ; this line looks interesting.
and eax, 1
ret
Questions
If I understand correctly MOVZX adds 0s at the beginning. As you can see in the next line it ANDs the value with 1. The question is: does MOVZX provide any value here? I mean wouldn't it work with a normal MOV? I need only the first bit there right?
I sadly couldn't find a "speed comparison" between MOV vs MOVZX. Can someone tell me does one perform better than the other (I'm assuming that MOVZX is slower, because it has to go and "clear out" the bits. If I'm not wrong)?
Related
This question already has answers here:
Why does Clang generate different code for reference and non-null pointer arguments?
(2 answers)
Why is gcc allowed to speculatively load from a struct?
(6 answers)
Boolean values as 8 bit in compilers. Are operations on them inefficient?
(3 answers)
Closed 6 months ago.
Let's assume there's the following code:
#include <stdbool.h>
typedef struct {
bool a;
bool b;
} MyStruct2;
bool g(MyStruct2 *s) {
return s->a || s->b;
}
bool g2(MyStruct2 *s) {
return s->a | s->b;
}
int main() {
return 0;
}
Which compiles into this:
g:
movzx eax, BYTE PTR [rdi]
test al, al
jne .L1
movzx eax, BYTE PTR [rdi+1]
.L1:
ret
g2:
movzx eax, BYTE PTR [rdi]
or al, BYTE PTR [rdi+1]
ret
main:
xor eax, eax
ret
g2 seems to be shorter and it does not include any jump. So why does gcc not optimize g to the same code as g2? None of the members of MyStruct2 is volatile (or otherwise special), so it should be safe to evaluate s->b in g in all cases (even if s->a is true and it would not be required to evaluate s->b).
Why doesnt gcc produce the shorter code without a jump?
Thanks
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.
This question already has answers here:
How does argument passing and returning values work in C/C++ on x86 at the assembly level? [closed]
(1 answer)
Passing Arguments C -> NASM -> C
(2 answers)
Passing various parameters from C to Assembler
(2 answers)
Closed 1 year ago.
Hi I have already written a program in Assembly 64 bit mode in connection with C, that counts the number of left and right brackets check here:
bits 64
section .data
extern g_left, g_right, g_str
section .text
global count
count:
enter 0,0
mov eax, 0
mov ebx, 0
mov ecx, 0
.back:
cmp [g_str + eax], byte 0
je .out
cmp [g_str + eax], byte '['
jne .right
inc ebx
.right:
cmp [g_str + eax], byte ']'
jne .skip
inc ecx
.skip:
inc eax
jmp .back
.out:
mov [g_l], ebx
mov [g_r], ecx
leave
ret
C code:
#include <stdio.h>
void count();
char g_str[] = "[[[]]]][[32423]][234dsfsdf";
int g_left, g_right;
int main()
{
count();
printf("left = %d and right = %d\n", g_left, g_right);
}
What I want is to use this assembly code but change it a bit so that a function that is called in C with a string as input and just prints the number of brackets. Also, I want it in 32-bit mode this time. It should look like this:
int brackets( char *t_str );
I'm new to assembly and confused on how to change my code, please help me.
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.
I am having a lot of trouble accessing a value in an array of chars at a specific location. I am using inline-assembly in C++ and using visual studio (if that is of any help). Here is my code:
char* addTwoStringNumbers(char *num1)
{
// here is what I have tried so far:
movzx eax, num1[3];
mov al, [eax]
}
When I debug, I can see that num1[3] is the value I want but I can't seem to make either al or eax equal that value, it seems to always be some pointer reference. I have also played around with Byte PTR with no luck.
I'm not good neither at inline assembly, neither at MASM syntax, but here are some hints:
1) Try this:
mov eax, num1 ;// eax points to the beggining of the string
movsx eax, [eax + some_index] ;// movsx puts the char num1[some_index] in eax with sign extend.
(movzx is for unsigned char, so we used movsx)
2) You need to pass the value from eax to C. The simpliest way is to declare a variable and to put results there: int rez; __asm { mov rez, eax; };
3) If you want to write the whole function in assembly, you should consider using the naked keyword (and read about calling conventions). If not, make sure you preserve registers and don't damage the stack.
Looks like someone's doing their ICS 51 homework! Follow ruslik's advice and you'll be done in no time.