I have some assembly code below that I don't really understand. My thoughts are that it is meaningless. Unfortunately I can't provide any more instruction information. What would the output in C be?
0x1000: iretd
0x1001: cli
0x1002: in eax, dx
0x1003: inc byte ptr [rdi]
0x1005: add byte ptr [rax], al
0x1007: add dword ptr [rbx], eax
0x1009: add byte ptr [rax], al
0x100b: add byte ptr [rdx], 0
0x100e: add byte ptr [rax], al
Thanks
The first four bytes (if I did reconstruct them correctly) form 32 bit value 0xFEEDFACF.
Putting that into google led me to:
https://gist.github.com/softboysxp/1084476#file-gistfile1-asm-L15
%define MH_MAGIC_64 0xfeedfacf
Aren't you by accident disassembling Mach-o x64 executable from Mac OS X as raw machine code, instead of reading meta data of file correctly, and disassembling only code section?
P.S. in questions like this one, rather include also the source machine code data, so experienced people may check disassembly by targetting different platform, like 32b x86 or 16b real mode code, or completely different CPU, which may help in case you would mistakenly treat machine code with wrong target platform disassembly. I had to first assemble your disassembly to see the raw bytes.
iretd is "return from interrupt", cli is "clear interrupt flag" which means disable all maskable interrupts. The C language does not understand the concept of an interrupt, so it is unlikely that this was compiled from C. In fact, this isn't a single complete fragment of code.
Also add byte ptr [rdx], 0 is adding 0 to a value which doesn't make sense to me unless it is the result of an unoptimised compilation or the result of disassembling something that isn't code.
Related
I'm having some issues at the moment, I'm not sure if this is the problem or not with my program, but this is one thing that I'm not 100% about, so I'm going to use it as a learning opportunity.
I have this instruction: in al, 0x60 to read the scancode from the keyboard.
I'm trying to send this scancode to a function written in C. The C function declaration looks like: void cFunction(unsigned int scancode).
So basically, here is what I'm doing:
in al, 0x60
movzx EAX, AL
push EAX
call Cfunction
The goal is to get a value like this into the C function: 0x10, which would mean the Q was pressed, 0x11 the W was pressed, 0x12 is E, and so on...
Questions:
Is what I'm doing passing the right value to the function or not?
Is the result going to be different if I were to push only AX instead of EAX?
I only need the byte AL, but obviously I cannot push AL, so I've been zero extending it to EAX. So, let's say if Q was pressed and I compared it like: if(scancode == 0x10), would this interpret correctly no matter that EAX vs AX was pushed? Or do I only need to get the value of AL into the scancode? If not, how can I go about getting AL to the function?
Answer depends on what calling convention does your C compiler use. If it is standard cdecl than yes, generally you do it right.
Some notes:
It is better to use C data types with exact size in bytes like uint32_t than int which size isn't fixed. These data types are defined in stdint.h
If you want to use AX instead EAX, you must define your function as
void cFunction(uint16_t scancode).
Since AL is a part of AX (and EAX) it is better to just erase AX (or EAX) before reading key scancode than extend it with MOVZX after reading. Typical way for it in assembly:
XOR register with itself
XOR EAX, EAX
Moving zero in register
MOV EAX, 0
is also correct, but XOR usually is a bit faster (and using it for register erase is some kind of tradition now)
So there are a few things to talk about here. Let's cover them one at a time.
First, I'm assuming you're running either without an OS (i.e., making your own OS) or running in an OS like MS-DOS that doesn't get in the way of I/O. As Olaf rightly pointed out, in al, 0x60 isn't going to work on a modern, protected-mode OS; nor will it work on a USB keyboard (unless you're running in an emulator or virtual machine that is pretending to provide a classic PS/2 keyboard).
Second, I'm assuming you're programming on a 32-bit CPU. The C ABI (application binary interface) is different for a 16-bit CPU, a 32-bit CPU, and a 64-bit CPU, so the code will read differently depending on which CPU you're using.
Third, port 60h is a weird beast, and it's been a long time since I wrote a driver for it. The values you read in aren't the values you think you're going to read in a lot of the time, and there are the E0h extended codes, and there's the behavior of the Pause key. Writing a bug-free keyboard driver is a lot harder than it looks. But let's ignore all that for this question.
So let's assume you have no OS to get in the way, and a 32-bit CPU, and only the most basic keystrokes. How would you pass data from the keyboard to a C function? Pretty much the way you did:
in al, 0x60
movzx eax, al
push eax
call cFunction
Why is this correct?
Well, the first line loads an 8-bit register with the keyboard; and it must be al because that's the only 8-bit register that in can write to.
The 32-bit C ABI expects a function's parameters to be pushed onto the stack, in reverse calling order. So in order to call the C function, there must be a push instruction before it. However, in 32-bit mode, all push instructions are 32-bit-sized, so you can only push eax, ebx, esi, edi, and so on: You can't push al directly. (Even if you could — and technically, you can, using direct stack writes — it would be misaligned, because in 32-bit mode, every item pushed must be aligned to a 4-byte boundary.) So the only way to push the value is first to promote it from 8 bits to 32 bits, and movzx does that nicely.
There are, for what it's worth, other ways to do it. You could clear eax before the in:
xor eax, eax
in al, 0x60
push eax
call cFunction
This solution is a bit worse than the original solution for performance; it has the cost of a partial register stall: The processor internally doesn't actually keep al as a part of eax, but rather as a separate register; any attempts to mix the different-sized sub-pieces of the registers together involves the processor stalling before being able to do so: When you push eax here, the processor realizes that al got mutated by the previous instruction, and stalls for a clock cycle to quickly mash al's bits into eax so it still looks like al was actually a part of eax.
It's worth pointing out that if you're in classic 16-bit mode (8086, or '286 protected mode), the calling sequence is slightly different:
in al, 0x60
movzx ax, al
push ax
call cFunction
In this case, int is 16-bit-sized, so doing everything as 16 bits is correct. Alternatively, in 64-bit mode, you need to use rax instead:
in al, 0x60
movzx rax, al
push rax
call cFunction
Even though the cFunction may have been compiled with int being only 32 bits, the stack-alignment requirements in 64-bit mode mandate that a 64-bit value would be pushed. The C function will correctly read out the 64-bit value as a 32-bit value, but you can only push it as 64 bits.
So there you have it. Various ways of interacting with the C ABI to get your port data into your function, depending on your CPU and environment.
I found x86 lea instructions in an executable file made using clang and gcc.
The lea instructions are after the ret instruction as shown below.
0x???????? <func>
...
pop %ebx
pop %ebp
ret
lea 0x0(%esi,%eiz,1),%esi
lea 0x0(%edi,%eiz,1),%edi
0x???????? <next_func>
...
What are these lea instructions used for? There is no jmp instruction to the lea instructions.
My environment is Ubuntu 12.04 32-bit and gcc 4.6.3.
It's probably not anything--it's just padding to let the next function start at an address that's probably a multiple of at least 8 (and quite possibly 16).
Depending on the rest of the code, it's possible that it's actually a table. Some implementations of a switch statement, for example, use a constant table that's often stored in the code segment (even though, strictly speaking, it's more like data than code).
The first is a lot more likely though. As an aside, such space is often filled with 0x03 instead. This is a single-byte debug-break instruction, so if some undefined behavior results in attempting to execute that code, it immediately stops execution and breaks to the debugger (if available).
I am trying to make sure that I understand the SI and DI registers. My background in assembly language is somewhat limited to 6502, so bear with me here.
I have a quick example of how I would go about using SI as a simple counter. I am a bit concerned that I might be misusing this register though.
mov si, 0 ; set si to 0
mov cx, 5 ; set cx to 5 as we will count down to 1
do:
mov ah, 02h ; setup 02h DOS character output interrupt
mov dl, [table + si] ; grab our table with the si offset
add dl, '0' ; convert to ascii integer
int 21h ; call DOS service
inc si ; increment si
loop do ; repeat unto cx = 0
ret
table: db 1,2,3,4,5
---
OUTPUT:> 12345
Is this the right way to use SI? I know in 6502 assembly, you can use the X and Y registers to offset arrays / tables. However, in my studies of x86, I am starting to realize how much more there is to work with. Such as how CX is automatically decremented in the 'loop' instruction.
I am hoping that moving forward, I will be able to save resources by writing efficient code.
Thank you in advance for your input.
This use of SI is perfectly fine. SI has the benefit of being a preserved register in most Intel calling conventions. Also, historically, SI was one of the few registers that you could use as an index in a memory load operation; in a modern Intel CPU, any register would do.
SI still gets some special treatment with the lods instruction.
Your program actually works fine. Adding org $100 at the beginning, I managed to compile it with FASM and run in DosBox:
On the 6502 you have two index registers (X and Y) that you can use in different ways (direct, indirect, indirect indexed, indexed indirect, ...).
On the x86 you have 4 registers that can be used as pointer registers: BX, BP, SI and DI (in 32-bit mode you can use nearly all registers)
BX and DI can be combined (Example: [BX+DI+10])
BP is typically used for storing the old stack pointer when entering a function (when using a C compiler). However there is no missuse of registers (unless you use the stack pointer for something different) when you program in assembler. You cannot do anything wrong!
But be careful: On the x86 (in 16-bit mode) you also have to care about the segment registers - this is what the 6502 does not have!
These registers are needed because you can only address 64 KiB using a 16-bit register but 8086 has an 1 MiB address space. To solve this an address is composed of a 16-bit segment and a 16-bit offset so an address is effectively not 16 but 32 bits long. The exact meaning of the first 16 bits depends on the operating mode of the CPU.
The following segment registers are present:
CS: CS:IP is the instruction pointer
SS: SS:SP is the stack pointer; used for SP and BP pointer operations by default
DS: Used for all other pointer operations (all but SP and BP) by default
ES: Additional register
FS, GS: Additional registers since 80386
You can overwrite the default segment register to be used:
MOV AX,ES:[SI+100] ; Load from ES:SI+100 instead of DS:SI+100
String operations (like movsb) always access DS:SI and ES:DI (you cannot change the segment register for such operations).
That's an alright use of SI. But you could use several other registers in its base (although beware that unlike 32-bit x86, 16-bit x86 code limits the set of registers on which indexing is supported. The ModRegR/M structure governs this.)
You might want to consider doing an add si, table before the loop and mov dl, [si] inside it. It makes the loop slightly easier for the human to read, because there's one less variable in play.
I'm beginner with asm, so I've been researching for my question for a while but answears were unsatisfactory. I'm wondering how to display PSW content on standard output. Other thing, how to display Instruction Pointer value ? I would be very gratefull if ypu could give me a hint (or better a scratch of code). It may be masm or 8086 as well (actually I don't know wthat is the difference :) )
The instruction pointer is not directly accessible on the x86 family, however, it is quite straightforward to retrieve its value - it will never be accurate though.
Since a subroutine call places the return address on the stack, you just need to copy it from there and violá! You have the address of the opcode following the call instruction:
proc getInstructionPointer
push bp
mov bp,sp
mov ax,[word ptr ss:bp + 2]
mov sp,bp
pop bp
ret
endp getInstructionPointer
The PSW on the x86 is called the Flags register. There are two operations that explicitly reference it: pushf and popf. As you might have guessed, you can simply push the Flags onto the stack and load it to any general purpose register you like:
pushf
pop ax
Displaying these values consists of converting their values to ASCII and writing them onto the screen. There are several ways of doing this - search for "string output assembly", I bet you find the answer.
To dispel a minor confusion: 8086 is the CPU itself, whereas MASM is the assembler. The syntax is assembler-specific; MASM assembly is x86 assembly. TASM assembly is x86 assembly as well, just like NASM assembly.
When one says "x86 Assembly", he/she is referencing any of these (or others), talking about the instruction set, not the dialect.
Note that the above examples are 16bit, indtended for 8086 and won't work on 80386+ in 32bit mode
I'm porting chunk of code from MASM to C inline assembler (x86, Windows, MS VC)
Foolowing is not a real code, just spoof to give an idea. Let's say I have some data defined as static array or even a code chunk between two labels, and I need to get size of it.
label1:
bla bla bla
label2:
....
mov eax, (offset label2 - offset label1)
Such a code works in MASM like a charm, but in C I get following error message:
"error C2425: '-' : non-constant expression in 'second operand'"
I can get compiled:
mov eax, offset label1
mov eax, offset label2
I expect compiler to evaluate (offset label1 - offset label2) at compile time, but it looks like I'm wrong. I can't add offsets as well (why? these are just two integers added during compilation...?)
Sure, I can get
mov eax, offset label2
mov edx, offset label1
sub eax, edx
compiled, but that's an extra code just for calculating a constant.
Can someone explain me please, what is wrong in my code?
Can it be something caused by relocation? How to push it through?
Looking forward to an answer,
thank you.
Yes, it can be caused by the threat of relocation but also threat of variable length instructions dealing with relative jumps. Most likely because of some minor trouble, the assembler writers took the easy way out and implemented a 1 pass or a two pass compiler that makes final decisions as soon as possible. And thus some convenient expressions are unsupported.
As already suggested in the comment, the assembler still probably supports mov + sub combination.
The real assembler is probably running over the code in several passes before it has gotten fixed addresses for all the labels. For example, some jumps have a short and a long form depending on how far you want to jump. If you have such a jump between the labels, the distance depends on where the jump is going to.
The C compiler might leave some of that to the linker/loader and not have the values fixed at compile time.
You could very well get the addres calculation code down to two instructions
mov EAX, offset Label2
sub EAX, offset Label1
I don't think this will exactly ruin the performance of the code.