I'm using IDA Pro to disassemble the following C code: However looking at the disassembly below it seems to me incomplete. The data is never initialized (as per C code) even though it does appear to be loaded into the stack however the procedure (nullsub_1) that is located at 00401040 makes no use of the data ? Am I making a correct assessment or am I missing something ??? I have used Visual C++ 6/2005 to compile the C code.
#include <stdio.h>
#include <windows.h>
struct a
{
char s[10];
BYTE b;
int i;
};
a al;
void init(a);
void main()
{
init(al);
};
void init(a c)
{
for(int j = 0; j < 10; j++) c.s[j] = 'A';
c.b = 10;
c.i = 10000;
};
.text:00401000 ; int __cdecl main(int argc,const char **argv,const char *envp)
.text:00401000 _main proc near ; CODE XREF: start+AFp
.text:00401000
.text:00401000 argc = dword ptr 4
.text:00401000 argv = dword ptr 8
.text:00401000 envp = dword ptr 0Ch
.text:00401000
.text:00401000 mov ecx, dword_4084C0
.text:00401006 mov edx, dword_4084C4
.text:0040100C sub esp, 10h
.text:0040100F mov eax, esp
.text:00401011 mov [eax], ecx
.text:00401013 mov ecx, dword_4084C8
.text:00401019 mov [eax+4], edx
.text:0040101C mov edx, dword_4084CC
.text:00401022 mov [eax+8], ecx
.text:00401025 mov [eax+0Ch], edx
.text:00401028 call nullsub_1
.text:0040102D add esp, 10h
.text:00401030 retn
.text:00401030 _main endp
.text:00401030
.text:00401030 ;
.text:00401031 align 10h
.text:00401040
.text:00401040
.text:00401040
.text:00401040 nullsub_1 proc near ; CODE XREF: _main+28p
.text:00401040 retn
.text:00401040 nullsub_1 endp
Your source code has no side effects other than just writing to memory. The compiler eliminates those writes as useless.
You may have better luck if you compile it in Debug mode (instead of Release) or turn off some compiler optimizations.
Alternatively, accesses to variables defined as volatile will be preserved, so you can add volatile in your code.
Related
im having a small issue with my assembly function that i made.
; Im failing super hard at writing this
; Function.
.MODEL c, small
.DATA?
.DATA
curpos_ PROTO C columns_:BYTE, rows_:BYTE
.CODE
public curpos_
curpos_ PROC C columns_:BYTE, rows_:BYTE
mov dh, columns_
mov dl, rows_
mov bh, 0
mov ah, 2
int 10h
ret
curpos_ ENDP
END
And my C file in which i prototype the assembly function.
#include<stdio.h>
#include<conio.h>
#include<math.h>
void clrscr(void);
extern char _columns, _rows;
extern void _curpos(char _columns, char _rows);
void arcradius() {
float w;
float h;
float radi = w / 2.0;
float value;
clrscr();
...
_curpos(20,40);
getch();
arcradius();
}
The issue im having is that my C program is not giving the assembly function the right arguments, in my C file i use _curpos(20,40) but it doesn't use the values in the parentheses. Instead it uses some garbage number from the previous scanf(); input.
Is there something im mis-declaring, prototyping incorrectly, or forgot?
I'm using OpenWatcom and MASM 6.11.
Thanks, Noah "MadDog" Buzelli
EDIT:
Here is the fixed assembly function
; Im failing super hard at writing this
; Function.
.MODEL small
.DATA?
.DATA
curpos PROTO C _columns:BYTE, _rows:BYTE
.CODE
public curpos
curpos PROC C _columns:BYTE, _rows:BYTE
push bx
mov dh, BYTE PTR _columns
mov dl, BYTE PTR _rows
mov bh, 0
mov ah, 2
int 10h
pop bx
ret 4
curpos ENDP
END
And here is my C prototype
extern void __stdcall curpos(char columns, char rows);
Thank you Mgetz :)
So you need to specify the Calling convention for the assembly method. By default open watcom uses __stdcall
So it should look something like this:
extern void __stdcall curpos(char _columns, char _rows);
This asm is probably right, but untested. We're doing everything manually, not relying on MASM's magic to set up BP and calculate the position of args on the stack.
_columns$ = 4 ; size = 1
_rows$ = 6 ; offsets relative to the frame pointer
; saved-BP at [bp+0], ret addr at [bp+2], first arg at [bp+4]
_curpos#4 PROC ; COMDAT
push bp
mov bp, sp ; for access to args on the stack, [sp] isn't valid
push bx ; save/restore the caller's BX
mov dh, BYTE PTR _columns$[bp]
mov dl, BYTE PTR _rows$[bp]
mov bh, 0 ; page=0
mov ah, 2
int 10h ; int 10h / AH=2 - BIOS Set cursor position
pop bx
pop bp ; no mov sp,bp needed, SP is already good
ret 4 ; pop ret addr, then SP+=4
_curpos#4 ENDP
For what it's worth it may be better to use inline assembly for this instead of doing a full implementation in asm. If you use inline asm the compiler takes care of all of this, you just have to get the inputs into registers, not write code that returns.
C code
#include <stdio.h>
int fibonacci(int);
int main()
{
int x = fibonacci(3);
printf("Fibonacci is : %d",x);
return 0;
}
Assembly
section .text
global fibonacci
fibonacci:
push ebp;
mov ebp, esp;
; initialize
mov dword [prev], 0x00000000;
mov dword [cur], 0x00000001;
mov byte [it], 0x01;
mov eax, dword [ebp + 8]; // n = 3
mov byte [n], al;
getfib:
xor edx,edx;
mov dl, byte [n];
cmp byte [it] , dl;
jg loopend;
mov eax,dword [prev];
add eax, dword [cur];
mov ebx, dword [cur];
mov dword [prev], ebx;
mov dword [cur] , eax;
inc byte [it];
jmp getfib;
loopend:
mov eax, dword [cur];
pop ebp;
ret;
section .bss
it resb 1
prev resd 1
cur resd 1
n resb 1
I was trying to run this assembly function in C code and on debugging , i saw that value in variable x in C code is right but there is some error coming when i use the printf function
Need Help on it
Command to compile:
nasm -f elf32 asmcode.asm -o a.o
gcc -ggdb -no-pie -m32 a.o ccode.c -o a.out
Click Below Pictures if they seem blurred
Below is debug before printf execute
Below is after printf execute
Your code does not preserve the ebx register which is a callee-preserved register. The main function apparently tries to do some rip-relative addressing to obtain the address of the format string for printf using ebx as a base register. This fails because your code overwrote ebx.
To fix this issue, make sure to save all callee-saved registers before you use them and then restore their value on return. For example, you can do
fibonacci:
push ebp
mov ebp, esp
push ebx ; <---
...
pop ebx ; <---
pop ebp
ret
I'm trying to link main.c program with procedure.asm. I have the following C program and Assembly program.
main.c
#include <Windows.h>
#include <iostream>
using namespace std;
extern "C" {
void ClearUsingIndex(int[], int);
}
static int Array[10] ={1, 2, 3, 4, 5, 6, 7, 8, 9, -1};
int main()
{
int size = 10;
ClearUsingIndex( Array, size);
system("pause");
return 0;
}
procedure.asm
; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.50727.1
TITLE c:\Users\GS\documents\visual studio 2012\Projects\ClearIndex\ClearIndex\procedure.cpp
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES
PUBLIC ?ClearUsingIndex##YAXQAHH#Z ; ClearUsingIndex
EXTRN __RTC_InitBase:PROC
EXTRN __RTC_Shutdown:PROC
; COMDAT rtc$TMZ
rtc$TMZ SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
rtc$TMZ ENDS
; COMDAT rtc$IMZ
rtc$IMZ SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
rtc$IMZ ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; COMDAT ?ClearUsingIndex##YAXQAHH#Z
_TEXT SEGMENT
_i$ = -8 ; size = 4
_Array$ = 8 ; size = 4
_size$ = 12 ; size = 4
?ClearUsingIndex##YAXQAHH#Z PROC ; ClearUsingIndex, COMDAT
; File c:\users\gs\documents\visual studio 2012\projects\clearindex\clearindex\procedure.cpp
; Line 2
push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 4
mov DWORD PTR _i$[ebp], 0
jmp SHORT $LN3#ClearUsing
$LN2#ClearUsing:
mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax
$LN3#ClearUsing:
mov eax, DWORD PTR _i$[ebp]
cmp eax, DWORD PTR _size$[ebp]
jge SHORT $LN4#ClearUsing
; Line 5
mov eax, DWORD PTR _i$[ebp]
mov ecx, DWORD PTR _Array$[ebp]
mov DWORD PTR [ecx+eax*4], 0
jmp SHORT $LN2#ClearUsing
$LN4#ClearUsing:
; Line 6
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
?ClearUsingIndex##YAXQAHH#Z ENDP ; ClearUsingIndex
_TEXT ENDS
END
I did some research and I found the following source and followed the instructions: Guide to Using Assembly in Visual Studio .NET
But I get the following error when I compile the assembly file.
error A1017: missing source filename
I google the error but all the methods I tried don't seem to work.
I am trying to get a sense of how I should use const in C code. First I didn't really bother using it, but then I saw a quite a few examples of const being used throughout. Should I make an effort and go back and religiously make suitable variables const? Or will I just be waisting my time?
I suppose it makes it easier to read which variables that are expected to change, especially in function calls, both for humans and the compiler. Am I missing any other important points?
const is typed, #define macros are not.
const is scoped by C block, #define applies to a file (or more strictly, a compilation unit).
const is most useful with parameter passing. If you see const used on a prototype with pointers, you know it is safe to pass your array or struct because the function will not alter it. No const and it can.
Look at the definition for such as strcpy() and you will see what I mean. Apply "const-ness" to function prototypes at the outset. Retro-fitting const is not so much difficult as "a lot of work" (but OK if you get paid by the hour).
Also consider:
const char *s = "Hello World";
char *s = "Hello World";
which is correct, and why?
How do I best use the const keyword in C?
Use const when you want to make it "read-only". It's that simple :)
Using const is not only a good practice but improves the readability and comprehensibility of the code as well as helps prevent some common errors. Definitely do use const where appropriate.
Apart from producing a compiler error when attempting to modify the constant and passing the constant as a non-const parameter, therefore acting as a compiler guard, it also enables the compiler to perform certain optimisations knowing that the value will not change and therefore it can cache the value and not have to read it fresh from memory, because it won't have changed, and it allows it to be immediately substituted in the code.
C const
const and register are basically the opposite of volatile and using volatile will override the const optimisations at file and block scope and the register optimisations at block-scope. const register and register will produce identical outputs because const does nothing on C at block-scope on gcc C -O0, and is redundant on -O1 and onwards, so only the register optimisations apply at -O0, and are redundant from -O1 onwards.
#include<stdio.h>
int main() {
const int i = 1;
printf("%d", i);
}
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 1
mov eax, DWORD PTR [rbp-4] //load from stack isn't eliminated for block-scope consts on gcc C unlike on gcc C++ and clang C, even though value will be the same
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
In this instance, with -O0, const, volatile and auto all produce the same code, with only register differing c.f.
#include<stdio.h>
const int i = 1;
int main() {
printf("%d", i);
}
i:
.long 1
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR i[rip] //load from memory
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
pop rbp
ret
with const int i = 1; instead:
i:
.long 1
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov eax, 1 //saves load from memory, now immediate
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
pop rbp
ret
C++ const
#include <iostream>
int main() {
int i = 1;
std::cout << i;
}
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 1 //stores on stack
mov eax, DWORD PTR [rbp-4] //loads the value stored on the stack
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
leave
ret
#include <iostream>
int main() {
const int i = 1;
std::cout << i;
}
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 1 //stores it on the stack
mov esi, 1 //but saves a load from memory here, unlike on C
//'register' would skip this store on the stack altogether
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
leave
ret
#include <iostream>
int i = 1;
int main() {
std::cout << i;
}
i:
.long 1
main:
push rbp
mov rbp, rsp
mov eax, DWORD PTR i[rip] //load from memory
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
#include <iostream>
const int i = 1;
int main() {
std::cout << i;
}
main:
push rbp
mov rbp, rsp
mov esi, 1 //eliminated load from memory, now immediate
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov eax, 0
pop rbp
ret
C++ has the extra restriction of producing a compiler error if a const is not initialised (both at file-scope and block-scope). const also has internal linkage as a default on C++. volatile still overrides const and register but const register combines both optimisations on C++.
Even though all the above code is compiled using the default implicit -O0, when compiled with -Ofast, const surprisingly still isn't redundant on C or C++ on clang or gcc for file-scoped consts. The load from memory isn't optimised out unless const is used, even if the file-scope variable isn't modified in the code. https://godbolt.org/z/PhDdxk.
Compiling this simple function with MSVC2008, in Debug mode:
int __cdecl sum(int a, int b)
{
return a + b;
}
I get the following disassembly listing:
int __cdecl sum(int a, int b)
{
004113B0 push ebp
004113B1 mov ebp,esp
004113B3 sub esp,0C0h
004113B9 push ebx
004113BA push esi
004113BB push edi
004113BC lea edi,[ebp-0C0h]
004113C2 mov ecx,30h
004113C7 mov eax,0CCCCCCCCh
004113CC rep stos dword ptr es:[edi]
return a + b;
004113CE mov eax,dword ptr [a]
004113D1 add eax,dword ptr [b]
}
004113D4 pop edi
004113D5 pop esi
004113D6 pop ebx
004113D7 mov esp,ebp
004113D9 pop ebp
004113DA ret
There are some parts of the prolog I don't understand:
004113BC lea edi,[ebp-0C0h]
004113C2 mov ecx,30h
004113C7 mov eax,0CCCCCCCCh
004113CC rep stos dword ptr es:[edi]
Why is this required?
EDIT:
After removing the /RTC compiler option, as was suggested, most of this code indeed went away. What remained is:
int __cdecl sum(int a, int b)
{
00411270 push ebp
00411271 mov ebp,esp
00411273 sub esp,40h
00411276 push ebx
00411277 push esi
00411278 push edi
return a + b;
00411279 mov eax,dword ptr [a]
0041127C add eax,dword ptr [b]
}
Now, why is the: sub esp, 40h needed? It's as if place is being allocated for local variables, though there aren't any. Why is the compiler doing this? Is there another flag involved?
This code is emitted due to the /RTC compile option. It initializes all local variables in your function to a bit pattern that is highly likely to generate an access violation or to cause unusual output values. That helps you find out when you forgot to initialize a variable.
The extra space in the stack frame you see allocated is there to support the Edit + Continue feature. This space will be used when you edit the function while debugging and add more local variables. Change the /ZI option to /Zi to disable it.
and in any case of buffer overflow (if you would overwrite local variables) you will end up in a field of "int 3" opcodes:
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
int 3 ; 0xCC
...
that can be catched by the debugger, so you can fix your code