I have a program that was an example from our textbook, however when i put it in visual studio i get all kinds of errors. I am very new to Assembly, so I don't really know what this code is supposed to do, and i don't know why it is not working. Here is the code:
.model flat,c
.code
; extern "C" int CalcResult1_(int a, int b, int c);
CalcResult1_ proc
push ebp
mov ebp,esp
mov eax,[ebp+8]
mov ecx,[ebp+12]
mov edx,[ebp+16]
add eax,ecx
imul eax,edx
pop ebp
ret
CalcResult1_ endp
end
Here are the errors it gives:
1>------ Build started: Project: CompOrgHW2, Configuration: Debug Win32 ------
1>assembly_.asm
1>g:\comporghw2\comporghw2\assembly_.asm(1): error C2059: syntax error: '.'
1>g:\comporghw2\comporghw2\assembly_.asm(2): error C2059: syntax error: '.'
1>g:\comporghw2\comporghw2\assembly_.asm(7): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>g:\comporghw2\comporghw2\assembly_.asm(7): error C2365: 'CalcResult1_': redefinition; previous definition was 'function'
1>g:\comporghw2\comporghw2\assembly_.asm(4): note: see declaration of 'CalcResult1_'
1>g:\comporghw2\comporghw2\assembly_.asm(7): error C2146: syntax error: missing ';' before identifier 'proc'
1>Done building project "CompOrgHW2.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Related
I'm using Visual Studio 2017 Community to build a test console C++ application. I need to include an assembly function into that project:
extern "C" void* __fastcall getBaseFS(void);
To include an asm file I right-clicked the project and went to "Build dependencies" -> "Build Customization" and checked "masm" in the list there.
I can then add an asm file by right-clicking my project -> Add New item -> and then add "asm_x64.asm" file where I write my x86-64 asm code:
.code
getBaseFS PROC
mov ecx, 0C0000100H ; IA32_FS_BASE
rdmsr
shl rdx, 32
or rax, rdx
ret
getBaseFS ENDP
END
This works in a 64-bit project.
The problem is that when I switch solution platform from x64 to x86:
my asm file needs to change. So in a sense I need to include a different "asm_x86.asm" file into compilation that is used only for x86 builds vs. x64 builds.
What's the best way to automate this switch?
OK, thanks to Michael Petch, I got it solved. Had to put both x64 and x86 code in one .asm file.
(There's another proposed option to deal with build configuration, but I prefer the method I'm showing here. I had a bad luck with those build configurations disappearing when solutions were moved from computer to computer.)
So, I'm not sure why using IFDEF RAX works, and Microsoft's own proposed ifndef X64 doesn't. But oh well. If anyone knows, please post a comment.
asm_code.asm file:
IFDEF RAX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; x64 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; WinAPI to call
extrn Beep : proc
.data
align 8
beep_freq:
dq 700 ; hz
beep_dur:
dq 200 ; ms
str_from:
db "Hail from x64 asm", 0
.code
useless_sh_t_function__get_GS_a_string_and_beep PROC
; parameter = CHAR** for a string pointer
; return = value of GS register selector
mov rax, str_from
mov [rcx], rax
mov rdx, qword ptr [beep_dur]
mov rcx, qword ptr [beep_freq]
call Beep
mov rax, gs
ret
useless_sh_t_function__get_GS_a_string_and_beep ENDP
ELSE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; x86 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.686p
.XMM
.model flat, C
.data
align 4
beep_freq dd 700 ; hz
beep_dur dd 200 ; ms
str_from db "Hail from x86 asm", 0
.code
; WinAPI to call
extrn stdcall Beep#8 : proc
useless_sh_t_function__get_GS_a_string_and_beep PROC
; parameter = CHAR** for a string pointer
; return = value of GS register selector
mov eax, [esp + 4]
mov [eax], OFFSET str_from
push dword ptr [beep_dur]
push dword ptr [beep_freq]
call Beep#8
mov eax, gs
ret
useless_sh_t_function__get_GS_a_string_and_beep ENDP
ENDIF
END
main.cpp file:
#include "stdafx.h"
#include <Windows.h>
extern "C" {
size_t useless_sh_t_function__get_GS_a_string_and_beep(const CHAR** ppString);
};
int main()
{
const char* pString = NULL;
size_t nGS = useless_sh_t_function__get_GS_a_string_and_beep(&pString);
printf("gs=0x%Ix, %s\n", nGS, pString);
return 0;
}
Good that you found a way to handle your use case.
However, if you have more asm files, or only need them for some build types, you could also change the settings for each individual file for the parts where it differs from the project defaults.
Just right-click a file name to get to its individual properties.
To have an asm file included in x64 builds only, you can use these settings:
And then exclude it from 32-bit builds:
These settings are available for all file type, not only for .asm files.
I wrote a script to build an Android NDK application, and the source is below:
#include <stdio.h>
#include <stdlib.h>
#define LOG_ID_RADIO 1
#define ANDROID_LOG_DEBUG 3
#define LOG_TAG "TEST_LOG"
#define LOGD(...) printf(ANDROID_LOG_DEBUG,LOG_TAG ,VA_ARGS);
int main()
{
size_t datalen = 0;
LOGD("data length error: %d", datalen); <-- Please notice the string: "error:"
return 0;
}
The script is below:
cd C:/workspace/ndkTest/ndk-build/TestCC/jni
echo ====
call ndk-build -C C:/workspace/ndkTest/ndk-build/TestCC/jni -B
set path=C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r15c;%path%
echo error=%ERRORLEVEL%
pause
Reproduce steps:
Download the project: testcc.zip, extract this .zip file, remember the build.bat location, for example: my build.bat location.
Open the build.bat file, maybe you need change two things:
C:/workspace/ndkTest/ndk-build/TestCC/jni <-- build.bat location
C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r15c <-- NDK Location
In Visual Studio, create an Android Makefile Project, right click this project and select Properties, the default setting, find NMake → General → Build Command Line, change it to your build.bat location, like this.
Build this solution.
When I use the string error:,
LOGD("data length error: %d", datalen);
this project will result in build failed. Error log:
1>------ Build started: Project: Project14, Configuration: Debug Win32 ------
1>====
1>make: Entering directory `C:/workspace/ndkTest/ndk-build/TestCC/jni'
1>[arm64-v8a] Compile : testtime <= timetest.c
1>C:/workspace/ndkTest/ndk-build/TestCC/jni/./timetest.c(16,2): warning G5552ABC2: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion]
1>EXEC : LOGD("data length error : %d", datalen);
1> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1>C:/workspace/ndkTest/ndk-build/TestCC/jni/./timetest.c:10:26: note: expanded from macro 'LOGD'
1>#define LOGD(...) printf(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__);
1> ^~~~~~~~~~~~~~~~~
1>C:/workspace/ndkTest/ndk-build/TestCC/jni/./timetest.c:7:27: note: expanded from macro 'ANDROID_LOG_DEBUG'
1>#define ANDROID_LOG_DEBUG 3
1> ^
1>C:/Users/v-shenya/AppData/Local/Android/Sdk/ndk-bundle/build//../sysroot/usr/include\stdio.h:129:24: note: passing argument to parameter '__fmt' here
1>int printf(const char* __fmt, ...) __printflike(1, 2);
1> ^
1>1 warning generated.
1>[arm64-v8a] Executable : testtime
1>[arm64-v8a] Install : testtime => libs/arm64-v8a/testtime
1>make: Leaving directory `C:/workspace/ndkTest/ndk-build/TestCC/jni'
1>error=0
1>Press any key to continue . . .
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\VC\VCTargets\Microsoft.MakeFile.Targets(44,5): error MSB3073: The command "C:\workspace\ndkTest\ndk-build\TestCC\jni\build.bat" exited with code -1.
1>Done building project "Project14.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
But when I change error: to error (trailing space) or errdor:, it just doesn't put "error" and ":" together:
LOGD("data length errdor: %d", datalen); or
LOGD("data length error %d", datalen);
This project will build with success:
1>------ Build started: Project: Project14, Configuration: Debug Win32 ------
1>====
1>make: Entering directory `C:/workspace/ndkTest/ndk-build/TestCC/jni'
1>[arm64-v8a] Compile : testtime <= timetest.c
1>C:/workspace/ndkTest/ndk-build/TestCC/jni/./timetest.c(16,2): warning G5552ABC2: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion]
1> LOGD("data length error %d", datalen);
1> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1>C:/workspace/ndkTest/ndk-build/TestCC/jni/./timetest.c:10:26: note: expanded from macro 'LOGD'
1>#define LOGD(...) printf(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__);
1> ^~~~~~~~~~~~~~~~~
1>C:/workspace/ndkTest/ndk-build/TestCC/jni/./timetest.c:7:27: note: expanded from macro 'ANDROID_LOG_DEBUG'
1>#define ANDROID_LOG_DEBUG 3
1> ^
1>C:/Users/v-shenya/AppData/Local/Android/Sdk/ndk-bundle/build//../sysroot/usr/include\stdio.h:129:24: note: passing argument to parameter '__fmt' here
1>int printf(const char* __fmt, ...) __printflike(1, 2);
1> ^
1>1 warning generated.
1>[arm64-v8a] Executable : testtime
1>[arm64-v8a] Install : testtime => libs/arm64-v8a/testtime
1>make: Leaving directory `C:/workspace/ndkTest/ndk-build/TestCC/jni'
1>error=0
1>Press any key to continue . . .
1>Done building project "Project14.vcxproj".
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
My Visual Studio 2017 version is 15.6.6. Is this a bug of MSBuild? How can I fix this?
My project is very huge, and changing the string error: was not a good idea.
MSBuild parses the output of any command it executes for standardized error or warning messages. Having error : in the output of your bat will be detected by MSBuild as an actual error message and cause the build to be marked as failure.
You can see the error detection code of MSBuild here and a blog post from 2006 that describes this feature.
Now you have several options to solve this:
Change your project to use the Exec command to run the bat with the IgnoreStandardErrorWarningFormat property:
<Exec Command="path/to/your/batfile.bat" IgnoreStandardErrorWarningFormat="true"></Exec>
Change the text in your code:
LOGD("invalid data length: %d", datalen);
Fix the compiler warning that causes that line to be printed out in the first place.
As we know, assembly files(.S) would get preprocessing before assembling, but I found that after preprocessing there may be struct/function prototypes in the resulting assembly files, How would the gnu as deal with these prototypes? Just ignored it?
For example, the following command:
gcc -E -o tmp.result arch/x86/boot/copy.S -Iinclude/ -Iarch/x86/include/
and the resulting assembly file (tmp.result) is:
# 1 "arch/x86/boot/copy.S"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "arch/x86/boot/copy.S"
# 11 "arch/x86/boot/copy.S"
# 1 "include/linux/linkage.h" 1
# 1 "include/linux/compiler.h" 1
# 5 "include/linux/linkage.h" 2
# 1 "include/linux/stringify.h" 1
# 6 "include/linux/linkage.h" 2
# 1 "include/linux/export.h" 1
# 26 "include/linux/export.h"
struct kernel_symbol
{
unsigned long value;
const char *name;
};
# 7 "include/linux/linkage.h" 2
# 1 "arch/x86/include/asm/linkage.h" 1
# 8 "include/linux/linkage.h" 2
# 12 "arch/x86/boot/copy.S" 2
.code16
.text
GLOBAL(memcpy)
pushw %si
pushw %di
movw %ax, %di
movw %dx, %si
pushw %cx
shrw $2, %cx
rep; movsl
popw %cx
andw $3, %cx
rep; movsb
popw %di
popw %si
retl
ENDPROC(memcpy)
but when trying to assemble this file:
as -o tmp.o tmp.result
produce following error:
include/linux/export.h: Assembler messages:
include/linux/export.h:26: Error: no such instruction: `struct kernel_symbol'
include/linux/export.h:27: Error: junk at end of line, first unrecognized character is `{'
include/linux/export.h:28: Error: no such instruction: `unsigned long value'
include/linux/export.h:29: Error: no such instruction: `const char *name'
include/linux/export.h:30: Error: junk at end of line, first unrecognized character is `}'
arch/x86/boot/copy.S:20: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:34: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:36: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:49: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:51: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:58: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:60: Error: invalid character '(' in mnemonic
arch/x86/boot/copy.S:67: Error: invalid character '(' in mnemonic
It seems that the assembler can not deal with the struct in tmp.result. How can Linux source code(.S) get through the assembling?
as cannot process struct and function prototypes - they are just for the C compiler, and get "pulled in" in your preprocessing by mistake. In facts, if you look at the header that provides that struct definition, you'll see:
#ifndef __ASSEMBLY__
struct kernel_symbol
{
unsigned long value;
const char *name;
};
So, the header above is thought to be included both from assembly and from C, but you didn't define __ASSEMBLY__ to tell it that you are including it into an assembly file.
Interestingly, gcc does have a builtin __ASSEMBLER__ predefined macro to discriminate between an inclusion in an assembly file or a C file, but it seems that the kernel does not use it for historical reasons, relying instead on defining manually __ASSEMBLY__ when preprocessing assembly files.
Long story short: to get the correct output from the preprocessor, you should be doing something like
gcc -E -D__ASSEMBLY__ -o tmp.result arch/x86/boot/copy.S -Iinclude/ -Iarch/x86/include/
(disclaimer: I'm not entirely familiar with the kernel build process, the line above may have other problems with include paths, or maybe the correct way would be to invoke cpp instead of gcc or whatever - I don't know)
I've created in windows c++ project in Visual Studio to learn how to write asm functions.
So in my project I've got hello.asm with this simple code:
.686
.MODEL FLAT
.STACK
.DATA
.CODE
hello PROC
xor eax,eax
ret
hello ENDP
END
and asm_test.cpp with main function like this:
#include "stdafx.h"
#include <Windows.h>
extern "C" void hello();
int _tmain(int argc, _TCHAR* argv[])
{
hello();
return 0;
}
So in general ml.exe doesnt have any problem compiling asm file to hello.obj
but hello() function doesnt' know where should it be taken from. And here is what compiler tells me.
1>------ Построение начато: проект: asm_test, Конфигурация: Debug Win32 ------
1> Assembling hello.asm...
1>asm_test.obj : error LNK2019: ссылка на неразрешенный внешний символ _hello в функции _wmain
1>G:\renderer\asm_test\Debug\asm_test.exe : fatal error LNK1120: неразрешенных внешних элементов: 1
========== Построение: успешно: 0, с ошибками: 1, без изменений: 0, пропущено: 0 ==========
Sorry, it's on russion, but it's clear that it can not find hello function
change hello to be _hello plz. for your hello.asm, it should be:
.686
.MODEL FLAT
.STACK
.DATA
.CODE
_hello PROC
xor eax,eax
ret
_hello ENDP
END
I would like to attach to a running process using WinDbg, and modify a certain function's code to simply return on invocation (for educational purposes).
I have used the following commands:
uf dll!name
This gives me a disassembly of the function.
I have picked a specific address at a certain location and modified it to ret:
ew addr c3
This crashes every time, what am i doing wrong?
You need to make sure you do the appropriate clean up so the stack is left in a proper state. Depending on the calling convention the method usually pushes stuff on the stack as part of the prologue. This must be undone as part of the epilogue.
Here's an example of changing a JIT compiled method using WinDbg.
The code:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Message();
Console.ReadLine();
Message();
Console.WriteLine("done");
}
private static void Message()
{
Console.WriteLine("message");
}
}
}
I compiled this as Debug to prevent the compiler from inlining the calls to Message.
Then I ran the executable and attached the debugger at the call to ReadLine.
For managed code I need to use SOS.dll to locate the JIT compiled code. So I loaded SOS and found the address for the code as follows.
0:004> .loadby sos clr
0:004> !name2ee *!ConsoleApplication1.Program
Module: 04a11000
Assembly: mscorlib.dll
--------------------------------------
Module: 001b2e94
Assembly: ConsoleApplication1.exe
Token: 02000002
MethodTable: 001b37b4
EEClass: 001b125c
Name: ConsoleApplication1.Program
0:004> !dumpmt -md 001b37b4
EEClass: 001b125c
Module: 001b2e94
Name: ConsoleApplication1.Program
mdToken: 02000002
File: c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
BaseSize: 0xc
ComponentSize: 0x0
Slots in VTable: 7
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDe JIT Name
04d14960 04a16728 PreJIT System.Object.ToString()
04d08790 04a16730 PreJIT System.Object.Equals(System.Object)
04d08360 04a16750 PreJIT System.Object.GetHashCode()
04d016f0 04a16764 PreJIT System.Object.Finalize()
001bc019 001b37ac NONE ConsoleApplication1.Program..ctor()
002a0050 001b3794 JIT ConsoleApplication1.Program.Main(System.String[])
002a00a8 001b37a0 JIT ConsoleApplication1.Program.Message()
0:004> !u 001b37a0
Normal JIT generated code
ConsoleApplication1.Program.Message()
Begin 002a00a8, size 21
*** WARNING: Unable to verify checksum for c:\temp\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
c:\temp\ConsoleApplication1\ConsoleApplication1\Program.cs # 20:
002a00a8 55 push ebp <-- prologue
002a00a9 8bec mov ebp,esp
002a00ab 833d60311b0000 cmp dword ptr ds:[1B3160h],0 <-- start of method
002a00b2 7405 je ConsoleApplication1!ConsoleApplication1.Program.Message()+0x11 (002a00b9)
002a00b4 e8fb6ff570 call clr!JIT_DbgIsJustMyCode (711f70b4)
002a00b9 90 nop
c:\temp\ConsoleApplication1\ConsoleApplication1\Program.cs # 21:
002a00ba 8b0d34217403 mov ecx,dword ptr ds:[3742134h] ("message")
002a00c0 e82bd3ad04 call mscorlib_ni!System.Console.WriteLine(System.String) (04d7d3f0)
002a00c5 90 nop
c:\temp\ConsoleApplication1\ConsoleApplication1\Program.cs # 22:
002a00c6 90 nop
002a00c7 5d pop ebp <-- epilogue
002a00c8 c3 ret
Then I opened the Memory window and pointed it to 002a00ab which is the first part of the actual method body of Message and changed the two opcodes to 5d and c3 for pop edb and ret respectively. If I skipped the pop edb part the stack would be messed up and I would get an exception.
I hit Go and the application continued without printing "message" a second time.