I have a function written for th e x64 microsft macro assembler in visual studio 2005.
The function recieves 3 arguments:
theFunction PROC firstP:QWORD, secondP:QWORD, thirdP:QWORD
the x64 calling convention state the the first 4 arguments will reside in registers rcx, rdx, r8 & r9.
When I'm using the arguments in the function, I'm referencing the register them self and not the parameters:
mov r10, rcx ; Move firstP to r10
This causes the following warning:
warning A6004: procedure argument or local not referenced
How can I avoid or surpress this warning?
Is there any way to reference the parameters inside the function instead of using the registers?
Found the solution: I didn't need to declare the PROC the way I did. No need to declare the parameters that are passed to the function.
theFunction PROC
mov r10, rcx ;Move firstP to r10
Related
Here are the simplified versions of my two files:
macros.asm:
INCLUDE Irvine32.inc
mSampleMacro MACRO prompt_address
MOV EDX, prompt_address
CALL WriteString
ENDM
END
main.asm:
INCLUDE macros.asm
.data
titleMsg BYTE " TITLE",0
instructions BYTE "Insert instructions.",0
.code
main PROC
PUSH OFFSET titleMsg
PUSH OFFSET instructions
CALL DisplayTitleAndInstructions
Invoke ExitProcess,0
main ENDP
DisplayTitleAndInstructions PROC
PUSH EBP
MOV EBP, ESP
MOV EDX, [EBP + 12] ; title
CALL WriteString
CALL Crlf
CALL Crlf
MOV EDX, [EBP + 8] ; instructions
CALL WriteString
CALL Crlf
CALL Crlf
POP EBP
RET 12
DisplayTitleAndInstructions ENDP
I get the errors when building:
LNK2001 unresolved external symbol _mainCRTStartup Project Z:\project\LINK
LNK1120 1 unresolved externals Project D:\autodelete_noav\Debug\Project.exe
What I've tried: I have changed the entry point in the Project properties to main, but I get the same error with _main instead of _mainCRTStartup. When I change the main proc to be named _main I still get this error. I have tried changing include paths, including/excluding END in macros.asm, switching the System type of the linker to Windows/Console/Native (all give a similar error), etc.
I'm unsure whether it's something in the files themselves or in the way I'm configuring everything in Visual Studio.
Thanks in advance to anyone willing to help.
Thanks to Michael Petch, renaming macros.asm to macros.inc and removing the END statement fixed it.
I am studying assembler for the x86 family of processor architectures (32-bit and 64-bit) on Windows. It is not to say that I'm quite a beginner, but I probably don't know everything, at least about the syntax of the MASM assembler, as it seems.
I use the MASM assembler (for 64-bit programs) located in folders belonging to Visual Studio:
"..\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\ml64.exe"
Visual Studio 2019 is installed, and I use the MASM assembler from its folder. I have Windows 7 myself.
I made my program for a 32-bit system, and it was normally assembled by MASM for 32-bit programs and worked. Then I translated its code for a 64-bit architecture (and there are a few changes needed in the code there). But, when assembling it with MASM for 64-bit programs, MASM gave an error message that there was allegedly some unresolved "StartOfProgram" symbol. Here's what's in the console:
C:\Assembler>cd "C:\Assembler"
C:\Assembler>"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\ml64.exe" "C:\Assembler\Main.asm" /link /subsystem:windows /entry:StartOfProgram
Microsoft (R) Macro Assembler (x64) Version 14.29.30138.0
Copyright (C) Microsoft Corporation. All rights reserved.
Assembling: C:\Assembler\Main.asm
Microsoft (R) Incremental Linker Version 14.29.30138.0
Copyright (C) Microsoft Corporation. All rights reserved.
/OUT:Main.exe
Main.obj
/subsystem:windows
/entry:StartOfProgram
LINK : error LNK2001: unresolved external symbol StartOfProgram.
Main.exe : fatal error LNK1120: unresolved external symbols: 1
I spent about two weeks or month searching for solution to this error, but I didn't find it.
In general, it used to give an error message that allegedly there is some unresolved symbol "WinMainCRTStartup", but recently I kind of realized that it made such an entry point, because I did not explicitly specify entry point in the console (via the command "/entry:", which is in the console from above), but the problem about "unresolved external symbol" remained, even though I set the entry point where I needed it (that is, on "StartOfProgram").
Here is the code of my 64-bit version of the program that just has to output "Hello world" in a pop-up window:
option casemap:none ; As far as i understand, functions from Windows API without case sensitivity not works
; **** Importing what needs ****
includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x64\kernel32.lib" ; Downloading main static library to use main functions of Windows API
extern LoadLibraryA:near ; I load from static libraries functions used in this program
extern GetProcAddress:near
extern FreeLibrary:near
extern ExitProcess:near
; **** Declaring memory segment ****
.data
text db 'Hello world', 0 ; Text in "Text Box"'s window
header db 'Title of hello world', 0 ; Header of "Text Box"'s window
nameOfDLL db 'user32.dll', 0
nameOfProcedureOfDLL db 'MessageBoxA', 0
handlerToModule dd 0
addressOfProcedureOfDLL dq 0 ; In 64-bit operating system, addresses are 64-bit, so size of memory area that this label points to - is quad word (dq) (that is 64 bits)
.code
; **** Entry point to program ****
StartOfProgram: ; For some reason, MASM assembler recommends putting "_" sign before label of entry point to program, if it is 32-bit. Therefore in 64-bit I don't.
mov rcx, offset nameOfDLL
sub rsp, 40 ; Pointer shifting for alignment of stack and plus "shadow space" in stack. It needed by x64 calling convention
call LoadLibraryA ; I dynamically connect DLL so that i can then take function from it
add rsp, 40
mov qword ptr handlerToModule, rax
mov rcx, rax ; Functions from Windows API use stdcall convention. stdcall is agreement to pass function parameters to stack backwards, so rax is last. Rax still contains Windows' DLL address (Microsoft call it "handler") (after recent call to Loadlibrary function), so it's better to use register, processor works faster with registers
mov rdx, offset nameOfProcedureOfDLL
sub rsp, 40
call GetProcAddress
add rsp, 40
mov addressOfProcedureOfDLL, rax ; I save address of procedure that i took from GetProcAddress. In 64-bit operating system, addresses are 64-bit, so needs to transfer rax register and not eax
mov rcx, 0
mov rdx, offset text
mov r8, offset header
mov r9, 0
sub rsp, 40
call addressOfProcedureOfDLL ; It is better to immediately pass address of function through memory address label and not through register containing this address, because computer will still have to go to this address later and there is no point in wasting time reading from register of same address
add rsp, 40
mov rcx, offset handlerToModule
sub rsp, 40
call FreeLibrary
add rsp, 40
mov rcx, 0
sub rsp, 40
call ExitProcess
add rsp, 40
end
Here is the code of my 32-bit version of this program (which was normally assembled and worked):
.386 ; There indicates processor with minimal set of functions (since new Intel processors (in "x86" family of architectures) are compatible (so far) with instructions of old Intel processors of same family of architectures)
option casemap:none ; As far as i understand, functions from Windows API without case sensitivity not works
; **** Importing what needs ****
includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86\kernel32.lib" ; Downloading main static library to use main functions of Windows API
;includelib "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86\User32.lib"
extern _LoadLibraryA#4:near ; I load from static libraries a functions used in this program
extern _GetProcAddress#8:near
extern _FreeLibrary#4:near
extern _ExitProcess#4:near
.model flat
; **** Declaring a memory segment ****
.data
text db 'Hello world', 0 ; Text in "Text Box"'s window
header db 'Title of hello world', 0 ; Header of "Text Box"'s windowокна
nameOfDLL db 'user32.dll', 0
nameOfProcedureOfDLL db 'MessageBoxA', 0
handlerToModule dd 0
addressOfProcedureOfDLL dd 0
.code
; **** Entry point to program ****
_StartOfProgram: ; For some reason, MASM assembler recommends putting "_" sign before label of entry point to program, if it is 32-bit
push offset nameOfDLL
call _LoadLibraryA#4 ; I dynamically connect DLL so that i can then take function from it
mov handlerToModule, eax
push offset nameOfProcedureOfDLL
push eax ; Functions from Windows API use stdcall convention. stdcall is agreement to pass function parameters to stack backwards, so eax is last. Eax still contains Windows' DLL address (Microsoft call it "handler") (after recent call to Loadlibrary function), so it's better to use register, processor works faster with registers
call _GetProcAddress#8
mov addressOfProcedureOfDLL, eax ; I save address of procedure that i took from GetProcAddress
push 0
push offset header
push offset text
push 0
call addressOfProcedureOfDLL
push handlerToModule
call _FreeLibrary#4
push 0
call _ExitProcess#4
end _StartOfProgram
And here is result of 32-bit version of program:
Result of 32-bit version of program
The problem was been solved in comments. As said by #Peter Cordes and #David Wohlferd, I needed to publish my label in my program by directive "public" and then writing the name of the label, or rewrite my entry-point-label with using directive "proc" and "endp" with name of label at beginning of this directives.
I prefer a solution through the "public" directive, because I think it is closer to low-level programming. In this case, I had to make my label public in my program using the "public" directive, and then write the name of the label at the end of it, to become available to external programs. The MASM assembler, apparently, gave an error due to fact that it did not see it accessible from the outside and therefore did not consider it correct to assign it as the entry point, although it could guess that if I specify it as entry point, then it is available for switching to it from the outside. Apparently, the developers of MASM didn't do this.
Here is an example of using directive "public" in my program (I used directive "public"):
public StartOfProgram
And I noticed that I can put it anywhere in my code.
Here is an example of using directive "proc" and "endp" in my program:
StartOfProgram proc ; - Beginning of this directivical procedure
; ... there may be the code itself inside this directivical procedure
StartOfProgram endp ; - End of this directivical procedure
My code in the question had other errors, separate from the theme of this question; I've corrected it there.
I am trying to learn x64 assembler. I wrote "hello world" and tried to call printf using the following code:
EXTERN printf: PROC
PUBLIC hello_world_asm
.data
hello_msg db "Hello world", 0
.code
hello_world_asm PROC
push rbp ; save frame pointer
mov rbp, rsp ; fix stack pointer
sub rsp, 8 * (4 + 2) ; shadow space (32bytes)
lea rax, offset hello_msg
mov rcx, rax ; <---- QUESTION ABOUT THIS LINE
call printf
; epilog. restore stack pointer
mov rsp, rbp
pop rbp
ret
hello_world_asm ENDP
END
At the beginning I called printf without "mov rcx, rax", which ended up with access violation. Getting all frustrated I just wrote in C++ a call to printf and looked in the disassembler. There I saw the line "mov rcx, rax" which fixed everything, but WHY do I need to move RAX to RCX ??? Clearly I am missing something fundamental.
Thanks for your help!
p.s. a reference to good x64 assembler tutorial is more than welcome :-) couldn't find one.
It isn't required, this code just wastes an instruction by doing an lea into RAX and then copying to RCX, when it could do
lea rcx, hello_msg
call printf ; printf(rcx, rdx, r8, r9, stack...)
printf on 64-bit Windows ignores RAX as an input; RAX is the return-value register in the Windows x64 calling convention (and can also be clobbered by void functions). The first 4 args go in RCX, RDX, R8, and R9 (if they're integer/pointer like here).
Also note that FP args in xmm0..3 have to be mirrored to the corresponding integer register for variadic functions like printf (MS's docs), but for integer args it's not required to movq xmm0, rcx.
In the x86-64 System V calling convention, variadic functions want al = the number of FP args passed in registers. (So you'd xor eax,eax to zero it). But the x64 Windows convention doesn't need that; it's optimized to make variadic functions easy to implement (instead of for higher performance / more register args for normal functions).
A few 32-bit calling conventions pass an arg in EAX, for example Irvine32, or gcc -m32 -mregparm=1. But no standard x86-64 calling conventions do. You can do whatever you like with private asm functions you write, but you have to follow the standard calling conventions when calling library functions.
Also note that lea rax, offset hello_msg was weird; LEA uses memory-operand syntax and machine encoding (and gives you the address instead of the data). offset hello_msg is an immediate, not a memory operand. But MASM accepts it as a memory operand anyway in this context.
You could use mov ecx, offset hello_msg in position-dependent code, otherwise you want a RIP-relative LEA. I'm not sure of the MASM syntax for that.
The Windows 64-bit (x64/AMD64) calling convention passes the first four integer arguments in RCX, RDX, R8 and R9.
The return value is stored in RAX and it is volatile so a C/C++ compiler is allowed to use it as generic storage in a function.
Hello Stack Overflowers!
I have wrote a asm code file that i'm trying to build using ml64 (v14.00.23506.0)
but the assembler gives me weird output.. like there something wrong in line 1..
i'm sure there is nothing wrong with the code because it worked well on other ml64 version. it worked well with the ml64 from VS Community 2015, the current ml64 from VC++ BuildTools Tech-Preview gives me the error in the screenshot.
i tried ml64 from VS Express 2015 and VC BuildTools 2015 TP, both give same error.
ps. im building with a batch script that i wrote and coding in VIM.
can anyone guide me on how to overcome this issue?
-- UPDATED --
that's the cmd build error after i fixed the previous batch errors.
still weird error, can anyone understand?
(thats a test code)
includelib kernel32.lib
includelib user32.lib
EXTERN GetModuleHandleExW:PROC
EXTERN MessageBoxW:PROC
EXTERN ExitProcess:PROC
.DATA
ALIGN 4
pwszMessage WORD "H","e","l","l","o",","," ","W","o","r","l","d","!"
WORD 0
pwszCaption WORD "M","e","s","s","a","g","e","B","o","x"
WORD 0
hInstance QWORD 0
.CODE
entry PROC
sub rsp, 28h
xor rcx, rcx
mov rdx, rcx
lea r8, [hInstance]
call GetModuleHandleExW
lea rdx, [pwszMessage]
lea r8, [pwszCaption]
mov r9d, 40h
call MessageBoxW
call ExitProcess ; rcx suppose to hold 0 already
add rsp, 28h
ret
entry ENDP
END
I'm pretty new to x64-assembly on the Mac, so I'm getting confused porting some 32-bit code in 64-bit.
The program should simply print out a message via the printf function from the C standart library.
I've started with this code:
section .data
msg db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp
mov rbp, rsp
push msg
call _printf
mov rsp, rbp
pop rbp
ret
Compiling it with nasm this way:
$ nasm -f macho64 main.s
Returned following error:
main.s:12: error: Mach-O 64-bit format does not support 32-bit absolute addresses
I've tried to fix that problem byte changing the code to this:
section .data
msg db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp
mov rbp, rsp
mov rax, msg ; shouldn't rax now contain the address of msg?
push rax ; push the address
call _printf
mov rsp, rbp
pop rbp
ret
It compiled fine with the nasm command above but now there is a warning while compiling the object file with gcc to actual program:
$ gcc main.o
ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not
allowed in code signed PIE, but used in _main from main.o. To fix this warning,
don't compile with -mdynamic-no-pic or link with -Wl,-no_pie
Since it's a warning not an error I've executed the a.out file:
$ ./a.out
Segmentation fault: 11
Hope anyone knows what I'm doing wrong.
The 64-bit OS X ABI complies at large to the System V ABI - AMD64 Architecture Processor Supplement. Its code model is very similar to the Small position independent code model (PIC) with the differences explained here. In that code model all local and small data is accessed directly using RIP-relative addressing. As noted in the comments by Z boson, the image base for 64-bit Mach-O executables is beyond the first 4 GiB of the virtual address space, therefore push msg is not only an invalid way to put the address of msg on the stack, but it is also an impossible one since PUSH does not support 64-bit immediate values. The code should rather look similar to:
; this is what you *would* do for later args on the stack
lea rax, [rel msg] ; RIP-relative addressing
push rax
But in that particular case one needs not push the value on the stack at all. The 64-bit calling convention mandates that the fist 6 integer/pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, exactly in that order. The first 8 floating-point or vector arguments go into XMM0, XMM1, ..., XMM7. Only after all the available registers are used or there are arguments that cannot fit in any of those registers (e.g. a 80-bit long double value) the stack is used. 64-bit immediate pushes are performed using MOV (the QWORD variant) and not PUSH. Simple return values are passed back in the RAX register. The caller must also provide stack space for the callee to save some of the registers.
printf is a special function because it takes variable number of arguments. When calling such functions AL (the low byte of RAX) should be set to the number of floating-point arguments, passed in the vector registers. Also note that RIP-relative addressing is preferred for data that lies within 2 GiB of the code.
Here is how gcc translates printf("This is a test\n"); into assembly on OS X:
xorl %eax, %eax # (1)
leaq L_.str(%rip), %rdi # (2)
callq _printf # (3)
L_.str:
.asciz "This is a test\n"
(this is AT&T style assembly, source is left, destination is right, register names are prefixed with %, data width is encoded as a suffix to the instruction name)
At (1) zero is put into AL (by zeroing the whole RAX which avoids partial-register delays) since no floating-point arguments are being passed. At (2) the address of the string is loaded in RDI. Note how the value is actually an offset from the current value of RIP. Since the assembler doesn't know what this value would be, it puts a relocation request in the object file. The linker then sees the relocation and puts the correct value at link time.
I am not a NASM guru, but I think the following code should do it:
default rel ; make [rel msg] the default for [msg]
section .data
msg: db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp ; re-aligns the stack by 16 before call
mov rbp, rsp
xor eax, eax ; al = 0 FP args in XMM regs
lea rdi, [rel msg]
call _printf
mov rsp, rbp
pop rbp
ret
No answer yet has explained why NASM reports
Mach-O 64-bit format does not support 32-bit absolute addresses
The reason NASM won't do this is explained in Agner Fog's Optimizing Assembly manual in section 3.3 Addressing modes under the subsection titled 32-bit absolute addressing in 64 bit mode he writes
32-bit absolute addresses cannot be used in Mac OS X, where addresses are above 2^32 by
default.
This is not a problem on Linux or Windows. In fact I already showed this works at static-linkage-with-glibc-without-calling-main. That hello world code uses 32-bit absolute addressing with elf64 and runs fine.
#HristoIliev suggested using rip relative addressing but did not explain that 32-bit absolute addressing in Linux would work as well. In fact if you change lea rdi, [rel msg] to lea rdi, [msg] it assembles and runs fine with nasm -efl64 but fails with nasm -macho64
Like this:
section .data
msg db 'This is a test', 10, 0 ; something stupid here
section .text
global _main
extern _printf
_main:
push rbp
mov rbp, rsp
xor al, al
lea rdi, [msg]
call _printf
mov rsp, rbp
pop rbp
ret
You can check that this is an absolute 32-bit address and not rip relative with objdump. However, it's important to point out that the preferred method is still rip relative addressing. Agner in the same manual writes:
There is absolutely no reason to use absolute addresses for simple memory operands. Rip-
relative addresses make instructions shorter, they eliminate the need for relocation at load
time, and they are safe to use in all systems.
So when would use use 32-bit absolute addresses in 64-bit mode? Static arrays is a good candidate. See the following subsection Addressing static arrays in 64 bit mode. The simple case would be e.g:
mov eax, [A+rcx*4]
where A is the absolute 32-bit address of the static array. This works fine with Linux but once again you can't do this with Mac OS X because the image base is larger than 2^32 by default. To to this on Mac OS X see example 3.11c and 3.11d in Agner's manual. In example 3.11c you could do
mov eax, [(imagerel A) + rbx + rcx*4]
Where you use the extern reference from Mach O __mh_execute_header to get the image base. In example 3.11c you use rip relative addressing and load the address like this
lea rbx, [rel A]; rel tells nasm to do [rip + A]
mov eax, [rbx + 4*rcx] ; A[i]
According to the documentation for the x86 64bit instruction set http://download.intel.com/products/processor/manual/325383.pdf
PUSH only accepts 8, 16 and 32bit immediate values (64bit registers and register addressed memory blocks are allowed though).
PUSH msg
Where msg is a 64bit immediate address will not compile as you found out.
What calling convention is _printf defined as in your 64bit library?
Is it expecting the parameter on the stack or using a fast-call convention where the parameters on in registers? Because x86-64 makes more general purpose registers available the fast-call convention is used more often.