Problem trying to run Assembly in Visual Studio - c

I'm trying to run some assembly code in Visual Studio 2012 and call it in C just for testing purposes. As I have no experience writing assembly code I have no idea what is going wrong, so I would greatly appreciate some help!
I get the following errors trying to compile the code:
Error 5 error MSB3721: The command "ml.exe /c /nologo /Zi /Fo"Debug\callee.obj" /W3 /errorReport:prompt /Tacallee.asm" exited with code 1. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\BuildCustomizations\masm.targets 49 5 ProjetoASM
Error 2 error A2206: missing operator in expression C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 18 1 ProjetoASM
Error 3 error A2206: missing operator in expression C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 21 1 ProjetoASM
Error 4 error A2206: missing operator in expression C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 8 1 ProjetoASM
Error 1 error A2022: instruction operands must be the same size C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 15 1 ProjetoASM
And the Assembly code:
PUBLIC hello_from_asm
EXTERN puts:PROC
.model flat
.data
msg db 'Hello, world!',0xa
len equ $ - msg
.code
hello_from_asm PROC
mov edx,len
mov ecx,msg
mov ebx,1
mov eax,4
int 0x80
mov eax,1
int 0x80
hello_from_asm ENDP
END
This was supposed to output a "Hello, world!", so any other ideas that might work are also welcome.
C code for completeness:
#include <stdio.h>
extern void hello_from_asm();
int main(){
printf("Hello from C");
hello_from_asm();
return 0;
}

Those detailed MASM error messages tell it all.
mov ecx,msg
You're required to use MASM style. The above instruction tries to load the first byte of msg in a 32-bit register. That's the "size mismatch" error.
What you need is loading the address of msg in ECX. Use
mov ecx, offset msg
The other errors might be about not recognizing the 0x hexadecimal prefix. Try using the h hexadecimal suffix instead. (0Ah, 80h)
The above is easy enough to change, and your code will assemble fine. However don't run it because the int 80h instruction is a Linux system call that is not going to work on Visual Studio 2012 (Windows).

Example 32 bit Visual Studio | Masm program to print "Hello World". I included the most common directives. "legacy_stdio_definitions.lib" is used for VS2015 and later, since printf and scanf were changed to be inlined with the output of the C compiler. You may not need it for VS2012.
.686p ;enable instructions
.xmm ;enable instructions
.model flat,c ;use C naming convention (stdcall is default)
; include C libraries
includelib msvcrtd
includelib oldnames
includelib legacy_stdio_definitions.lib ;for scanf, printf, ...
.data ;initialized data
pfstr db "Hello world!",0dh,0ah,0
.data? ;uinitialized data
.stack 4096 ;stack (optional, linker will default)
.code ;code
extrn printf:near
public main
main proc
push offset pfstr ; 32-bit mode uses stack args
call printf
add esp,4 ; cdecl is caller-pops
xor eax,eax ; return 0
ret
main endp
end

Related

'printf' function and 'proc' directive behaving weird in ml64(masm x64)?

;this file -> test1.asm
includelib msvcrt.lib
includelib legacy_stdio_definitions.lib
extern _CRT_INIT: proc ;custom entrypoint needs c-runtime to be initialised by the programmer.
extern printf: proc
extern ExitProcess: proc
.data
msg db "hello world!", 13, 10, 0
.code
fun proc
sub rsp, 32 ;for shadow space
call _CRT_INIT ;called _CRT_INIT because I have my own entry point named "fun"
lea rcx,msg
call printf
add rsp, 32
call ExitProcess
fun endp
end
commandline for assembler: ml64 /nologo /c test1.asm
commandline for linker: link /entry:fun /subsystem:console test1.obj
This standalone assembly program seems to be working fine. But doing some changes(mentioned below) make the program crash.
1st change -> according to this link both libcmt.lib and msvcrt.lib statically links the native CRT startup (ie both can be used to call _CRT_INIT) into my code. The difference is msvcrt.lib is used with dll. As I don't have any dll I considered using libcmt.lib in place of msvcrt.lib but then the program crashes. Considering there is only printf function associated, that concludes printf function breaks the program. But why?
2nd change -> Now I tried calling this fun() function from a simple .C file. For that I made the necessary changes.
;this file -> test1.asm
;not including any libraries. linking the .c file make the libraries link too because that is in my libpath environment variable
;extern _CRT_INIT: proc ;no need of _CRT_INIT because now mainCRTStartup() will be the entrypoint and .c file will take care of initializing the c-runtime
extern printf: proc
;extern ExitProcess: proc ;no need of exitprocess. Instead i'm using ret instruction because I'm calling fun() from .c file.
.data
msg db "hello world!", 13, 10, 0
.code
fun proc c ;even if I replace 'c' with something like "abed" the program works. but if I dont give anything after proc then the program crashes.
sub rsp, 32 ;for shadow space
lea rcx,msg
call printf
add rsp, 32
ret
fun endp
end
//this file -> test2.c
#include <stdio.h>
#include <conio.h>
void fun(); //in C no need of extern keyword. extern is needed in c++
int main()
{
fun();
getch();
}
commandline for assembler: ml64 /nologo /c test1.asm
commandline for compiler: cl /nologo /c test2.c
commandline for linker: link test1.obj test2.obj
In the previous working example (ie. with msvcrt.lib) I don't have to give any suffixes after 'proc' directive. But in this case when I am calling 'fun' as a function from my C file I need to give anything like 'a'/'b'/combination('abcd') after 'proc' directive and only then the program works. If I don't give anything after 'proc' the program crashes. According to official MSDN documentation proc directive also accept language type. Even so wrong/random 'language type name' ie. any word seem to work. But how?
I tried many things like changing the libraries, using different version of printf (like vfprintf) and tried assigning more shadow space also googled much but unable to find any answer.

How to fix " Infinite Loop error on jumping to C code from bootloader"

I am actually trying to run C code to write my operating system kernel for studying how operating systems work. I am stuck on this infinite loop when the bootloader jumps to my C code. How should I prevent this error
Although my bootloader works correctly the problem comes when my bootloader jumps to the kernel code written in C as a.COM program. The main thing is that the dummy code just keeps on printing a character again and again although the code must run only once. It seems as if the main code is being called again and again. Here is the code for the startpoint.asm assembly header and bootmain.cpp file.
Here is the code for startpoint.asm which is used while linking at first so that the code can be invoked automatically. (Written in MASM )
Note: The code is loaded at the address 2000H:0000H.
;------------------------------------------------------------
.286 ; CPU type
;------------------------------------------------------------
.model TINY ; memory of model
;---------------------- EXTERNS -----------------------------
extrn _BootMain:near ; prototype of C func
;------------------------------------------------------------
;------------------------------------------------------------
.code
main:
jmp short start ; go to main
nop
;----------------------- CODE SEGMENT -----------------------
start:
cli
mov ax,cs ; Setup segment registers
mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct
mov ss,ax ; Make SS correct
mov bp,2000h
mov sp,2000h ; Setup a stack
sti
; start the program
call _BootMain
ret
END main ; End of prog
Code for bootmain.cpp
extern "C" void BootMain()
{
__asm
{
mov ah,0EH
mov al,'G'
int 10H
}
return;
}
The compiling and linker commands are as follows:
Code to compile bootmain.cpp:
CL.EXE /AT /G2 /Gs /Gx /c /Zl bootmain.cpp
Code to compile startpoint.asm:
ML.EXE /AT /c startpoint.asm
Code to link them both (In preserved order):
LINK.EXE /T /NOD startPoint.obj bootmain.obj
Expected output:
G
Actual Output:
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
Take a closer look at the end of start.
start is never called -- it is jumped to directly, and it sets up the stack itself. When _BootMain returns, the stack is empty; the ret at the end of start will pop garbage data from above the end of the stack and attempt to jump to it. If that memory contains zeroes, program flow will return to main.
You need to set up something specific to happen after _BootMain returns. If you just want the system to hang after executing _BootMain, insert an infinite loop (e.g. jmp .) to the end of start instead of the erroneous ret.
Alternatively, consider having your bootloader set up the stack itself and call the COM executable. When that returns, the bootloader can take appropriate action.

how to use inline assembly(NASM) for file I/O

I tried to write a char[] in stdout using inline NASM (note .intel_syntax and .att_syntax are added so it can be compiled with gcc)
but it doesn't write anything in stdout.
I am using Linux 16 (x86) on Virtual machine
Is it cause of char c[] ? ( I read by this way of compiling we cannot use memory variables but what to do instead?)
#include<stdio.h>
char c[] = "abcd";
int main(){
asm (".intel_syntax noprefix");
// write c into stdout
asm("mov EAX,4"); // 4: write
asm("mov EBX,1"); // 1: stdout
asm("mov ECX,c");
asm("mov EDX,5");
asm("int 0x80");
// exit program
asm("mov EAX,1")
asm("int 0x80")
asm (".att_syntax noprefix");
}
the output is nothing
The GNU assembler (which is what gcc uses) does not use NASM syntax. It rather uses a variant of Microsoft's MASM syntax where no brackets are needed to dereference a variable. Since you don't want to load the value of the c variable but rather its address, you need an offset keyword:
mov ecx, offset c
I strongly recommend you to avoid inline assembly as much as possible for learning assembly. Using inline assembly in gcc requires good knowledge of how exactly this whole thing works and writing random instructions usually leads to wrong code. Even your simple code is already fundamentally broken and would not work if it was any more complicated than that (so the compiler had a chance to try to use the registers you overwrote without telling).
Instead, put your assembly in a separate file and link it in. This sidesteps all issues you have with inline assembly and allows you to use NASM as you wanted. For example, try something like this:
main.c
char c[] = "abcd";
/* the function you define in print_c.asm */
extern void print_c();
int main() {
print_c(); /* call your assembly function */
}
print_c.asm
; pull in c defined in main.c
extern c
section .text
global print_c
print_c:
; write c to stdout
mov eax, 4
mov ebx, 1
mov ecx, c
mov edx, 5
int 0x80
; exit program
mov eax, 1
int 0x80
Then assemble, compile, and link with:
nasm -felf print_c.asm
cc -m32 -o print_c print_c.o main.c

If statements in masm: Syntax error in control flow directive

I am trying to use the if macro in MASM, but I keep getting the following error message from the MASM assembler: Syntax error in control flow directive. I'm still not sure what the syntax error is here: what is the correct syntax for if statements in MASM?
.686p
.model flat,stdcall
.stack 2048
.data
X byte 1;
ExitProcess proto, exitcode:dword
.code
start:
.IF(x > 1): ; "syntax error in control-flow directive"
mov ah, x;
.ENDIF
invoke ExitProcess, 0
end start
Remove the colon ":" after ). Also, you define X as a capital letter, but use the lowercase x, this is not valid. Assembly is case sensitive.

Undefined reference to multiply

I'm trying to call C function in assembler. This is my code:
C:
int multiply(int what)
{
return what * 2;
}
ASM:
extern multiply
start:
mov eax, 10
push eax
call multiply
jmp $
;empty
times 510-($-$$) db 0
dw 0xAA55
I'm compiling C code to elf by gcc (MinGW) and ASM code by NASM. I'm compiling it without any problems, but when I'm trying to use this code(for creating .bin file):
gcc -o test.bin work.o test.o
I' getting this error:
Does anybody know how to call C function from ASM code, compile it and link it to working .bin file? Please help.
Try to add '_' to multiply:
extern _multiply
Works for me in this simple example:
global _main
extern _printf
section .data
text db "291 is the best!", 10, 0
strformat db "%s", 0
section .code
_main
push dword text
push dword strformat
call _printf
add esp, 8
ret
Try "global multiply" instead of "extern multiply" in your .asm file. You shouldn't need the underscore for ELF (I don't think), but you can get Nasm to automagically add an underscore to anything "extern" or "global" by adding "--prefix _" to Nasm's command line.
Edit: I take that back, "extern" is correct. You seem not to have a "main". Try adding "--nostartfiles"
(may be only one hyphen) to gcc's command line.
Best,
Frank

Resources