Root > Solving bugs in your code > Bug reports > Assembler

Assembler

Previous pageReturn to chapter overviewNext page   

Assembler section shows disassembler machine code near exception. This section can be disabled in options.

 

Note: assembler section is automatically disabled for reporting leaks.

 

Disassembler listing does not provide any new information as compared to other information in bug report - because it simply duplicate content of your executable, but presents it in human-readable form. But this section can still be useful, because it saves you time on disassembling your exe/DLL file.

 

Assembler Information:

------------------------------------------------------------------------

; Base Address: $7F0000, Allocation Base: $400000, Region Size: 61440

; Allocation Protect: PAGE_EXECUTE_WRITECOPY, Protect: PAGE_EXECUTE_READ

; State: MEM_COMMIT, Type: MEM_IMAGE

;

;

; Unit9.TForm9.Button7Click (Line=747 - Offset=0)

; -----------------------------------------------

00000000007F0D20  55              PUSH RBP

00000000007F0D21  4883EC20        SUB  RSP, $20

00000000007F0D25  488BEC          MOV  RBP, RSP

00000000007F0D28  48894D30        MOV  [RBP+$30], RCX

00000000007F0D2C  48895538        MOV  [RBP+$38], RDX

;

; Line=748 - Offset=16

; --------------------

00000000007F0D30  488B0DA9ACC5FF  MOV  RCX, [REL -$003A5357] ; ($000000000044B9E0) Exception Data as ANSI: '¨ºD'; Data as UNICODE: '모D'

00000000007F0D37  B201            MOV  DL, 1

00000000007F0D39  4C8D0520000000  LEA  R8, [REL $00000020]   ; ($00000000007F0D60) Unit9.TForm9.Button7Click (Line=749) UNICODE: 'Error Message'

00000000007F0D40  E84BEBC6FF      CALL -$3914B5              ; ($000000000045F890) System.Exception.Create

00000000007F0D45  4889C1          MOV  RCX, RAX

00000000007F0D48  E823C3C1FF      CALL -$3E3CDD              ; ($000000000040D070) System._RaiseExcept <-- EXCEPTION

;

; Line=749 - Offset=45

; --------------------

00000000007F0D4D  488D6520        LEA  RSP, [RBP+$20]

00000000007F0D51  5D              POP  RBP

 

Example of disassembly output

 

Exception address will be listed in the middle of disassembly listing and marked with "<-- EXCEPTION" comment. Listing will go 15 CPU instructions in both directions (up/down) from exception address or until start/end of routine is found.

 

Note: exact value of exception address can be found in General section or CPU section.

 

Assembler section uses asm syntax compatible with Delphi's asm-blocks with minor exceptions (see below):

Each line starts with absolute address of that CPU instruction inside the module. Address is represented as 8 hex-characters for 32-bit code or 16 hex-characters for 64-bit code;
The next part is RAW dump which shows exact bytes of CPU instruction. These are 2 hex-characters per byte. Exact length of this block can vary depending on actual CPU instruction. For example, for x86-32 and x86-64 this can be from 2 hex-characters (1 byte) up to 30 hex-characters (15 bytes - which is maximum length of CPU instruction for x86). Raw bytes can be used to manually disassemble code* (see remark below);
Central piece is CPU instruction and (optional) arguments. Assembly syntax follows Delphi compiler with minor exceptions. Please note that instructions will use addresses and offsets instead of textual identifiers;
Each line may end with optional comment block. This optional comment can show:
oException line mark. "<-- EXCEPTION". This mark indicate address of CPU instruction which raised the exception. This mark can be shown only once per entire listing;
oAbsolute address. This value is shown if instruction references relative address and absolute address can be calculated. For example, MOV, JMP, and CALL instructions ("CALL -$3E3CDD ; ($000000000040D070)"). This value can also be shown for indirect values;
oIdentifier. This value is shown if there is debug information available for that address. For example: "CALL -$3E3CDD ; System._RaiseExcept". This value usually indicate routine's name and line for JMP and CALL instructions, but can also indicate code blocks for try/except statements. Please note that this value can show useless information for data references - if this data is stored inside code section, for example: "LEA R8, [REL $00000020] ; Unit9.TForm9.Button7Click (Line=749)";
oString data. This value is shown when instruction references AnsiString or UnicodeString constant. For example: "LEA R8, [REL $00000020] ; UNICODE: 'Error Message'". This value can not be false-positive, because EurekaLog analyzes string's header;
oCharacter data. This value is shown if instruction references some memory that can be interpreted as string (PAnsiChar and PWideChar). Note that this case does not include AnsiString and UnicodeString constants, because these were covered in previous item. This value is often false-positive because EurekaLog only checks for data to be readable and zero-terminated. Still, this value can be useful. For example, for MessageBox's text/captions. Example: "LEA RDX, [REL $000000BD] ; Data as ANSI: 'E'; Data as UNICODE: 'Error'". This value is always shows ANSI and Unicode interpretation of data. This value also shows references to code section, because PChar constants are often encoded right in code section.

 

CPU instructions are grouped in source lines. Each source line is marked with comment block above CPU instructions. Comment block indicate routine name, line number and byte offset. Each value is listed only if it was changed from previous line. For example, routine name is not shown if current line belongs to the same routine as previous line.

 

There is also a special comment block at the top of the section which shows general information about code page to which disassembled code belongs.

 

Note: disassembly listing uses ;-style comments instead of usual Delphi's //-style comments.

 

 

Absolute and relative addressing

EurekaLog's disassembler follows rules of Delphi's disassembler. For example, x86-32 assembler uses absolute addressing by default, but x86-64 assembler uses relative addressing by default. For example: "MOV EAX, [$10]". This instruction will be compiled into "MOV EAX, [ABS $10]" by 32-bit assembler. But the same instruction will be compiled into "MOV EAX, [REL $10]" (which means "MOV EAX, [RIP + $10]") by 64-bit assembler.

 

Delphi assembler supports ABS and REL modifier to alter addressing mode. It does not support [RIP + $10] or [$ + $10] syntax. ABS modifier is shown as + sign by Delphi's disassembler. For example, "MOV EAX, [ABS $10]" instruction will be disassembled by Delphi as "MOV EAX, [+$10]".

 

EurekaLog's disassembler always use REL and ABS modifiers to indicate addressing mode. REL/ABS modifiers are omitted for 32-bit code.

 

x86-64 is extension of x86-32. Thus, x86-64 tries to be compatible with x86-32 as much as possible. Still, there are differences - such as addressing mode. x86-32 prefers absolute addressing, while x86-64 prefers relative addressing to simplify writing PIC (Position Independent Code). This means that 64-bit code requires much less fix-ups when loading DLL to address which is different from preferred base address of this DLL. That's because 64-bit instructions works with relative addresses, so it doesn't use absolute addresses which needs to be fixed if code is loaded to another address.

 

Summary:

 

MOV [sym],       RAX  ; absolute for 32-bit, relative for 64-bit

MOV [REL sym],   RAX  ; relative

MOV [RIP + sym], RAX  ; relative, not supported by Delphi

MOV [$ + sym],   RAX  ; relative, not supported by Delphi

MOV [ABS sym],   RAX  ; absolute

MOV [+ sym],     RAX  ; absolute, Delphi disassembler only

 

 

64-bit values

Most 64-bit instructions works with 32-bit values. In 64-bit mode, immediates (that is, contants) and displacements (that is, offsets) are generally only 32 bits wide.

 

1.The only instruction which takes a full 64-bit immediate is: "MOV reg64, imm64". For example: "MOV RBX, $1234567890ABCDEF". Any other form of immediate will be 32-bit only (zero-extended to 64-bit prior to use, if needed).
2.The only instructions which take a full 64-bit displacement is loading or storing, using MOV, AL, AX, EAX or RAX (but no other registers) to an absolute 64-bit address. For example: "MOV RAX, [ABS $1234567890ABCDEF]". Address must be 64-bit absolute address (no registers are allowed in the effective address, and the address cannot be RIP-relative). Recipient register must be some form of AX register. Any other form of displacement will be 32-bit only (sign-extended prior to use, if needed).

 

The above means that you can not JMP or CALL to 64-bit absolute location specified with constant. JMP and CALL can only jump to a relative location within +/- 2 Gb from current instruction. If you need to jump to arbitrary 64-bit location then you have to use at least two instructions or indirect addressing:

 

MOV RAX, $1234567890ABCDEF

JMP RAX

 

or:

 

JMP [REL 0]

DB $12, $34, $56, $78, $90, $AB, $CD, $EF

 

 

(*) Note: automatic disassembling may be not possible in the following cases:

EurekaLog's disassembler may encounter unknown instruction's opcode. Currently there is support for Intel's and AMD's opcodes up to SSE 4.1 (including AMD's 3DNow opcodes). Newer opcodes will be not recognized. Currently there is no support for VEX and XOP opcodes (except for a few). There is no support for 3rd party opcodes (such as special virtual machine opcodes);
x86 architecture does not allow you to "move backward". I.e. you can't get 100% correct address of previous CPU instruction by having address of some valid CPU instruction. This makes 100% correct disassembling of code BEFORE exception address impossible. EurekaLog uses educated guesses (such as debug information or trying to walk forward from some address before exception), but these guesses may sometimes fail. This means that while exception address and listing below it will always be 100% accurate, but listing above exception address may show wrong values.

 

 

See also:




Send feedback... Build date: 2023-09-11
Last edited: 2023-03-07
PRIVACY STATEMENT
The documentation team uses the feedback submitted to improve the EurekaLog documentation. We do not use your e-mail address for any other purpose. We will remove your e-mail address from our system after the issue you are reporting has been resolved. While we are working to resolve this issue, we may send you an e-mail message to request more information about your feedback. After the issues have been addressed, we may send you an email message to let you know that your feedback has been addressed.


Permanent link to this article: https://www.eurekalog.com/help/eurekalog/bug_report_assembler.php