Go back after jump - if-statement

I have this code, I need check RCX register three times. I made a few lines of code (24-34 lines). In the first time (first jz), I move to true: label, but after I can't go back and check it the second time (28-30 lines). My program just finish everytime after the first jz. How can I go back and check it three time?
default REL
extern GetStdHandle
extern WriteFile
extern ExitProcess
section .data
true_msg db 'Yes', 0
true_msg_len equ $-true_msg
section .text
global _main
_main:
and rsp, -10h
sub rsp, 020h
mov rcx, -0Bh
call GetStdHandle
;jmp true
mov rcx, 2
cmp rcx, 2
jz true
mov rcx, 0
cmp rcx, 0
jz true
mov rcx, 1
cmp rcx, 0
jz true
;----------------
add rsp, 28h ; Restore Stack Pointer
;----------------
mov rcx, 0 ; RCX - first argument.
call ExitProcess
;----------------
xor rax, rax
ret
true:
mov rcx, rax
mov rdx, true_msg
mov r8, true_msg_len
xor r9, r9
push r9
sub rsp, 20h
call WriteFile
I want to get something like:
if(...){
...
}
if(...){
...
}
if(...){
...
}
I need every condition to be checked.

There is a missunderstanding on how to execute this. In a simple way:
if (test) {
//block1
}
if (test2) {
//block2
}
if(test3) {
//block3
}
(Pay attention on where those block1, block2 and block3 will appear in my next exemple)
Each if needs to test (the test into parenthesys) and then either go and execute the possibility it is true and the possibility it is not true.
So it would be something like this:
;first if, start by comparing:
mov rcx, 2
cmp rcx, 2
jnz false1 ;jumps for the false possibility of the first if
;here you type what will happen when the first if is executed (block1)
false1: ;here the first if is finnished, this label is the jump for not executing that first if
;then now you execute the second if:
;first compare:
mov rcx, 0
cmp rcx, 0
jnz false2 ;jumps for not executing the if block
;here is block2
false2:
;now here the last if, just like the last two:
mov rcx, 1
cmp rcx, 0
jnz false3
;here block3
false3:
;here is the rest of your code after those ifs
I changed the logic for jumping in false possibility instead of true (as you did) because in cases where there is no "else" block, it makes the code smaller than the way you did.

Related

I have an x86-64 program that only works properly when run from the gdb debugger

I have written a primitive version of malloc in x86 assembler as an exercise. The code uses a linked list to keep track of allocated memory blocks. I decided to add a function to walk the list and print out the meta data for each block and encountered this weird problem. When I run the code using gdb it works properly but when run directly without gdb it does not. When I print out an address returned by sbrk as a hex string it only prints correctly if run from gdb. If run repeatedly without gdb it prints a different number each run. I have cut the code down to the minimum needed to illustrate the problem. I have tried everything I can think of to find the problem. I'm sure that my itoh and printstring funcions are working correctly. I have tried linking with the c library and using puts but it does the same. I tried initializing all registers to zero. I have looked for any registers altered by the call to sbrk and saved and restored them across the call. Nothing has worked. Here is the code that illustrates the problem:
global _start,itoh,printstring
section .rodata
TRUE equ 1
FALSE equ 0
NULL equ 0
LF equ 10
sys_brk equ 12
exit_ok equ 0
sys_exit equ 60
sys_write equ 1
stdout equ 1
section .data
current_brk dq 1
linefeed db LF, NULL
msg1 db 'Test should print 0x403000 from constant: ', NULL
msg2 db 'Test should print 0x403000 from sys_brk return: ', NULL
number db '--------------------', NULL
section .text
_start: mov rdi, msg1
call printstring
mov rdi, 0x403000
mov rsi, number
mov rdx, TRUE
call itoh
mov rdi, number
call printstring
mov rax, sys_brk
syscall
mov [current_brk], rax
mov rdi, msg2
call printstring
mov rdi, [current_brk]
mov rsi, number
mov rdx, TRUE
call itoh
mov rdi, number
call printstring
.exit: mov rax, sys_exit
mov rdi, exit_ok
syscall
;
; itoh - rdi intger to convert
; - rsi address of string to return result
; - rdx if true add a newline to string
; return nothing
itoh: push rcx
push rax
xor r10, r10 ; r10 counts the digits pushed onto stack
mov r9, rdx ; save newline flag in r9
mov rax, rdi ; rax is bottom half of dividend
mov rcx, 16 ; rcx is divisor
.div: xor rdx, rdx ; zero rdx, top half of 128 bit dividend
div rcx ; divide rdx:rax by rcx
push rdx ; rdx is remainder
inc r10 ; increment digit counter
cmp rax, 0 ; is quotient zero?
jne .div ; no - keep dividimg by 16 and pushing remainder
.pop: mov byte[rsi], "0"
inc rsi
mov byte[rsi], "x"
inc rsi
.p0: pop r11 ; get a digit from stack
cmp r11, 10
jl .p1
sub r11, 10
add r11, "a"
jmp .p2
.p1: add r11, "0" ; convert to ascii char
.p2: mov byte[rsi],r11b ; copy ascii digit to string buffer
dec r10 ; decrement digit count
inc rsi ; point rsi to next char position
cmp r10, 0 ; is digit counter 0
jne .p0 ; no, go get another digit from stack
cmp r9, 0
je .exit
mov byte[rsi], LF
inc rsi
.exit: mov byte[rsi], NULL ; terminate string
pop rax
pop rcx
ret
;
; printstring - rdi is address of string
; return nothing
printstring:
push rcx ; sys_write modifies rcx
push rax ; sys_write modifies rax
xor rdx, rdx ; zero rdx, char count
mov rsi, rdi ; use rsi to index into string
.countloop:
cmp byte [rsi],NULL ; end of string?
je .countdone ; yes, finished counting
inc rdx ; no, count++
inc rsi ; point to next char
jmp .countloop
.countdone:
cmp rdx, 0 ; were there any characters?
je .printdone ; no - exit
mov rax, sys_write ; write system call
mov rsi, rdi ; address of string
mov rdi, stdout ; write to stdout
syscall ; number of bytes to write is in rdx
.printdone:
pop rax
pop rcx
ret
yasm -felf64 -gdwarf2 test.asm
ld -g -otest test.o
gdb test
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...
[?2004h(gdb) run
[?2004l
Starting program: /home/david/asm/test
Test should print 0x403000 from constant: 0x403000
Test should print 0x403000 from sys_brk return: 0x403000
[Inferior 1 (process 28325) exited normally]
[?2004h[?2004l
[?2004h(gdb) q
[?2004l
./test
Test should print 0x403000 from constant: 0x403000
Test should print 0x403000 from sys_brk return: 0x14cf000

Get device encryption support information

I want to detect the device encryption support in my program. This info is available in the System Information program. Please check out the screenshot below:
What kind of Win API functions are used/available to detect the device encryption support? What System Information program uses to detect it? I just need some information.
TL;DR: it uses undocumented functions from fveapi.dll (Windows Bitlocker Drive Encryption API). It seems to rely only on the TPM capabilities.
Note that I only spent like 15 mins on it, but I doubt I missed something crucial, althoug this might be possible.
A bit of Reverse engineering
Typed system information in search bar, saw it spawned msinfo32.exe. Put the binary in a disassembler. It uses a MUI file so I'll have to search for the strings in the MUI file and not the executable.
Searching Device Encryption Support leads to string ID 951 (0x3b7)
STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
951, "Device Encryption Support|%s"
Searching for the contant in the disassembler leads to a function named:
DeviceEncryptionDataPoints(struct CWMIHelper *, struct CPtrList *)
The load ing of the aforementioned string is almost right at the start:
.text:00000001400141E9 mov edx, 3B7h
.text:00000001400141EE lea rcx, [rsp+2C8h+var_280]
.text:00000001400141F3
.text:00000001400141F3 loc_1400141F3:
.text:00000001400141F3 ; try {
.text:00000001400141F3 call cs:__imp_?LoadStringW#CString##QEAAHI#Z ; CString::LoadStringW(uint)
So we are definitely in the right function.
It loads the fveapi.dll module:
.text:0000000140014269 xor edx, edx ; hFile
.text:000000014001426B mov r8d, 800h ; dwFlags
.text:0000000140014271 lea rcx, LibFileName ; "fveapi.dll"
.text:0000000140014278 call cs:__imp_LoadLibraryExW
Gets a pointer on FveQueryDeviceEncryptionSupport:
.text:00000001400142AB lea rdx, aFvequerydevice ; "FveQueryDeviceEncryptionSupport"
.text:00000001400142B2 mov rcx, rdi ; hModule
.text:00000001400142B5 call cs:__imp_GetProcAddress
And immediately calls the function (this is a protected CFG call, but it's here):
.text:00000001400142CA mov [rsp+2C8h+var_254], rbx
.text:00000001400142CF mov [rsp+2C8h+var_260], 14h
.text:00000001400142D7 mov [rsp+2C8h+var_25C], 1
.text:00000001400142DF mov [rsp+2C8h+var_258], 1
.text:00000001400142E7 lea rcx, [rsp+2C8h+var_260]
.text:00000001400142EC call cs:__guard_dispatch_icall_fptr
Return value
If the function fails:
.text:00000001400142EC call cs:__guard_dispatch_icall_fptr
.text:00000001400142F2 mov esi, eax
.text:00000001400142F4 test eax, eax
.text:00000001400142F6 js loc_1400143F0 ; check failure
We land here:
.text:00000001400143F7 mov edx, 2FFh
.text:00000001400143FC lea rcx, [rsp+2C8h+var_288]
.text:0000000140014401 call cs:__imp_?LoadStringW#CString##QEAAHI#Z ; CString::LoadStringW(uint)
The string 0x2FF (767) is:
767, "Elevation Required to View"
If the call succeed, the code checks one of the parameter which is definitly an out parameter:
.text:00000001400142EC call cs:__guard_dispatch_icall_fptr
.text:00000001400142F2 mov esi, eax
.text:00000001400142F4 test eax, eax
.text:00000001400142F6 js loc_1400143F0
.text:00000001400142FC cmp dword ptr [rsp+2C8h+var_254], ebx ; rbx = 0
.text:0000000140014300 jnz short loc_14001431D
.text:0000000140014302 mov edx, 3B8h
.text:0000000140014307 lea rcx, [rsp+2C8h+var_288]
.text:000000014001430C call cs:__imp_?LoadStringW#CString##QEAAHI#Z ; CString::LoadStringW(uint)
If it's 0, the string 0x3b8 (952) is used:
952, "Meets prerequisites"
Otherwise various failure functions are called.
Failure
In case of a failure, the UpdateDeviceEncryptionStateFailureString function is called:
.text:0000000140014325 lea r9, [rsp+2C8h+var_294] ; int *
.text:000000014001432A lea r8, [rsp+2C8h+var_290] ; int *
.text:000000014001432F mov edx, 3C1h ; unsigned int
.text:0000000140014334 lea rcx, [rsp+2C8h+var_288] ; struct CString *
.text:0000000140014339 call ?UpdateDeviceEncryptionStateFailureString##YAXPEAVCString##IPEAH1#Z ; UpdateDeviceEncryptionStateFailureString(CString *,uint,int *,int *)
Its main goal is to fetch some string from the resource file.
One that stands out is 0x3b9:
.text:0000000140013A37 mov edx, 3B9h
.text:0000000140013A3C mov rcx, rbx
.text:0000000140013A3F call cs:__imp_?LoadStringW#CString##QEAAHI#Z ; CString::LoadStringW(uint)
953, "Reasons for failed automatic device encryption"
Which is the case for me since I don't have a TPM.
Other Functions
All of the other functions called from the DeviceEncryptionDataPoints (at least to get the needed results) are all from the fveapi.dll.
There are a lot in a function called PerformIndividualHardwareTests(HINSTANCE hModule, struct CString *, int *, int *):
.text:0000000140013AEF lea rdx, aNgscbcheckisao ; "NgscbCheckIsAOACDevice"
.text:0000000140013AF6 mov [rbp+var_1F], 0
.text:0000000140013AFA mov rdi, r9
.text:0000000140013AFD mov [rbp+var_20], 0
.text:0000000140013B01 mov rsi, r8
.text:0000000140013B04 mov [rbp+var_1E], 0
.text:0000000140013B08 mov rbx, rcx
.text:0000000140013B0B call cs:__imp_GetProcAddress
.text:0000000140013B12 nop dword ptr [rax+rax+00h]
.text:0000000140013B17 mov r12, rax
.text:0000000140013B1A test rax, rax
.text:0000000140013B1D jz loc_140013CB9
.text:0000000140013B23 lea rdx, aNgscbcheckishs ; "NgscbCheckIsHSTIVerified"
.text:0000000140013B2A mov rcx, rbx ; hModule
.text:0000000140013B2D call cs:__imp_GetProcAddress
.text:0000000140013B34 nop dword ptr [rax+rax+00h]
.text:0000000140013B39 mov r15, rax
.text:0000000140013B3C test rax, rax
.text:0000000140013B3F jz loc_140013CB9
.text:0000000140013B45 lea rdx, aNgscbcheckhsti ; "NgscbCheckHSTIPrerequisitesVerified"
.text:0000000140013B4C mov rcx, rbx ; hModule
.text:0000000140013B4F call cs:__imp_GetProcAddress
.text:0000000140013B56 nop dword ptr [rax+rax+00h]
.text:0000000140013B5B mov r13, rax
.text:0000000140013B5E test rax, rax
.text:0000000140013B61 jz loc_140013CB9
.text:0000000140013B67 lea rdx, aNgscbcheckdmas ; "NgscbCheckDmaSecurity"
.text:0000000140013B6E mov rcx, rbx ; hModule
.text:0000000140013B71 call cs:__imp_GetProcAddress
There's also a registry key checked SYSTEM\CurrentControlSet\Control\BitLocker\AutoDE\HSTI:
.text:0000000140013C10 lea r8, ?NGSCB_AUTODE_HSTI_REQUIRED##3QBGB ; "HSTIVerificationRequired"
.text:0000000140013C17 mov [rsp+60h+pcbData], rax ; pcbData
.text:0000000140013C1C lea rdx, ?NGSCB_AUTODE_HSTI_PREREQS##3QBGB ; "SYSTEM\\CurrentControlSet\\Control\\Bit"...
.text:0000000140013C23 lea rax, [rbp+var_1C]
.text:0000000140013C27 mov r9d, 10h ; dwFlags
.text:0000000140013C2D mov [rsp+60h+pvData], rax ; pvData
.text:0000000140013C32 mov rcx, 0FFFFFFFF80000002h ; hkey
.text:0000000140013C39 and [rsp+60h+var_40], 0
.text:0000000140013C3F call cs:__imp_RegGetValueW
and some other functions (NgscbCheckPreventDeviceEncryption, NgscbGetWinReConfiguration, FveCheckTpmCapability, ...) , once again, all from the fveapi.dll module.
So basically the checks are all based on functions from this DLL. It seems that none of them are documented (as far as I can see with a quick search).
I didn't find anything around in the DeviceEncryptionDataPoints caller (which is basically the main() function), since the next calls are dealing with checking the hypervisor capabilities.

Mystery: casting a GNU C label pointer to a function pointer, with inline asm to put a ret in that block. Block being optimized away?

Firstly: This code is considered to be of pure fun, please do not do anything like this in production. We will not be responsible of any harm caused to you, your company or your reindeer after compiling and executing this piece of code in any environment. The code below is not safe, not portable and is plainly dangerous. Be warned. Long post below. You were warned.
Now, after the disclaimer: Let's consider the following piece of code:
#include <stdio.h>
int fun()
{
return 5;
}
typedef int(*F)(void) ;
int main(int argc, char const *argv[])
{
void *ptr = &&hi;
F f = (F)ptr;
int c = f();
printf("TT: %d\n", c);
if(c == 5) goto bye;
//else goto bye; /* <---- This is the most important line. Pay attention to it */
hi:
c = 5;
asm volatile ("movl $5, %eax");
asm volatile ("retq");
bye:
return 66;
}
For the beginning we have the function fun which I have created purely for reference to get the generated assembly code.
Then we declare a function pointer F to functions taking no parameters and returning an int.
Then we use the not so well known GCC extension https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html to get the address of a label hi, and this works in clang too. Then we do something evil, we create a function pointer F called f and initialize it to be the label above.
Then the worst of all, we actually call this function, and assign its return value to a local variable, called C and the we print it out.
The following is an if to check if the value assigned to the c is actually the one we need, and if yes go to bye so that he application exits normally, with exit code 66. If that can be considered a normal exit code.
The next line is commented out, but I can say this is the most important line in the entire application.
The piece of code after the label hi is to assign 5 to the value of c, then two lines of assembly to initialize the value of eax to 5 and to actually return from the "function" call. As mentioned, there is a reference function, fun which generates the same code.
And now we compile this application, and run it on our online platform: https://gcc.godbolt.org/z/K6z5Yc
It generates the following assembly (with -O1 turned on, and O0 gives a similar result, albeit a bit more longer):
# else goto bye is COMMENTED OUT
fun:
mov eax, 5
ret
.LC0:
.string "TT: %d\n"
main:
push rbx
mov eax, OFFSET FLAT:.L3
call rax
mov ebx, eax
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
cmp ebx, 5
je .L4
.L3:
movl $5, %eax
retq
.L4:
mov eax, 66
pop rbx
ret
The important lines are mov eax, OFFSET FLAT:.L3 where the L3 corresponds to our hi label, and the line after that: call rax which actually calls it.
And runs like:
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 66
TT: 5
Now, let's revisit the most important line in the application and uncomment it.
With -O0 we get the following assembly, generated by gcc:
# else goto bye is UNCOMMENTED
# even gcc -O0 "knows" hi: is unreachable.
fun:
push rbp
mov rbp, rsp
mov eax, 5
pop rbp
ret
.LC0:
.string "TT: %d\n"
main:
push rbp
mov rbp, rsp
sub rsp, 48
mov DWORD PTR [rbp-36], edi
mov QWORD PTR [rbp-48], rsi
mov QWORD PTR [rbp-8], OFFSET FLAT:.L4
mov rax, QWORD PTR [rbp-8]
mov QWORD PTR [rbp-16], rax
mov rax, QWORD PTR [rbp-16]
call rax
mov DWORD PTR [rbp-20], eax
mov eax, DWORD PTR [rbp-20]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
cmp DWORD PTR [rbp-20], 5
nop
.L4:
mov eax, 66
leave
ret
and the following output:
ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 66
so, as you can see our printf was never called, the culprit is the line mov QWORD PTR [rbp-8], OFFSET FLAT:.L4 where L4 actually corresponds to our bye label.
And from what I can see from the generated assembly, not a piece of code from the part after hi was added into the generated code.
But at least the application runs and at least has some code for comparing c to 5.
On the other end, clang, with O0 generates the following nightmare, which by the way crashes:
# else goto bye is UNCOMMENTED
# clang -O0 also doesn't emit any instructions for the hi: block
fun: # #fun
push rbp
mov rbp, rsp
mov eax, 5
pop rbp
ret
main: # #main
push rbp
mov rbp, rsp
sub rsp, 48
mov dword ptr [rbp - 4], 0
mov dword ptr [rbp - 8], edi
mov qword ptr [rbp - 16], rsi
mov qword ptr [rbp - 24], 1
mov rax, qword ptr [rbp - 24]
mov qword ptr [rbp - 32], rax
call qword ptr [rbp - 32]
mov dword ptr [rbp - 36], eax
mov esi, dword ptr [rbp - 36]
movabs rdi, offset .L.str
mov al, 0
call printf
cmp dword ptr [rbp - 36], 5
jne .LBB1_2
jmp .LBB1_3
.LBB1_2:
jmp .LBB1_3
.LBB1_3:
mov eax, 66
add rsp, 48
pop rbp
ret
.L.str:
.asciz "TT: %d\n"
If we turn on some optimization, for example O1, we get from gcc:
# else goto bye is UNCOMMENTED
# gcc -O1
fun:
mov eax, 5
ret
.LC0:
.string "TT: %d\n"
main:
sub rsp, 8
mov eax, OFFSET FLAT:.L3
call rax
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
.L3:
mov eax, 66
add rsp, 8
ret
and the application crashes, which is sort of understandable. Again, the compiler had entirely removed our hi section (mov eax, OFFSET FLAT:.L3 goes tiptoe to L3 which corresponds to our bye section) and unfortunately decided that it's a good idea to increase rsp before a ret so to be sure we end up somewhere totally different where we need to be.
And clang delivers something even more dubious:
# else goto bye is UNCOMMENTED
# clang -O1
fun: # #fun
mov eax, 5
ret
main: # #main
push rax
mov eax, 1
call rax
mov edi, offset .L.str
mov esi, eax
xor eax, eax
call printf
mov eax, 66
pop rcx
ret
.L.str:
.asciz "TT: %d\n"
1 ? How on earth did clang end up with this?
To some level I understand that the compiler decided that dead code after an if where both if and else go to the same location is not needed, but here my knowledge and insight stops.
So now, dear C and C++ gurus, assembly aficionados and compiler crushers, here comes the question:
Why?
Why do you think did the compiler decide that the two labels should be considered equivalent if we have added the else branch, or why did clang put there 1, and last but not least: someone with a deep understanding of the C standard could maybe point out where this piece of code deviated so badly from normality that we ended up in this really really weird situation.
someone with a deep understanding of the C standard could maybe point out where this piece of code deviated so badly from normality that we ended up in this really really weird situation.
You think the ISO C standard has anything to say about this code? It's chock full of UB and GNU extensions, notably pointers to local labels.
Casting a label pointer to a function pointer and calling through it is obviously UB. The GCC manual doesn't say you can do that. It's also UB to goto a label in another function.
You were only able to make that work by tricking the compiler into thinking that block might be reached so it's not removed, then using GNU C Basic asm statements to emit a ret instruction there.
GCC and clang remove dead code even with optimization disabled; e.g. if(0) { ... } doesn't emit any instructions to implement the ...
Also note that the c=5 in hi: compiles with optimization fully disabled (and else goto bye commented) to asm like movl $5, -20(%rbp). i.e. using the caller's RBP to modify local variables in the stack frame of the caller. So you have a nested function.
GNU C allows you to define nested functions that can access the local vars of their parent scope. (If you liked the asm you got from your experiment, you'll love the executable trampoline of machine-code that GCC stores to the stack with mov-immediate if you take a pointer to a nested function!)
asm volatile ("movl $5, %eax"); is missing a clobber on EAX. You step on the compiler's toes which would be UB if this statement was ever reached normally, rather than as if it were a separate function.
The use-case for GNU C Basic asm (no constraints / clobbers) is instructions like cli (disable interrupts), not anything involving integer registers, and definitely not ret.
If you want to define a callable function using inline asm, you can use asm("") at global scope, or as the body of an __attribute__((naked)) function.

Would the compiler optimize this expression into a temporary constant rather than resolve it every iteration?

I have the following loop:
for (unique_ptr<Surface>& child : Children)
{
child->Gather(hit);
if (hit && HitTestMode == HitTestMode::Content && child->MouseOver && !mouseOver)
{
mouseOver = true;
}
}
I wonder if the compiler (I use Visual Studio 2013, targeting x64 on Win7 upwards) would optimize the expression
hit && HitTestMode == HitTestMode::Content
into a temporary constant and use that rather than resolve the expression every iteration, similar to me doing something like this:
bool contentMode = hit && HitTestMode == HitTestMode::Content;
for (unique_ptr<Surface>& child : Children)
{
child->Gather(hit);
if (contentMode && child->MouseOver && !mouseOver)
{
mouseOver = true;
}
}
Bonus question:
Is checking for !mouseOver worth it (in order to skip the conditional mouseOver = true; if it has already been set)? Or is it faster to simply set it again regardless?
The answer to whether that optimization could even take place would depend on what hit, HitTestMode and HitTestMode::Content are and whether it's possible that they could be changed by the call to child->Gather().
If those identifiers are constants or local variables that the compiler can prove aren't modified, then it's entirely possible that the sub-expression hit && HitTestMode == HitTestMode::Content will be hoisted.
For example, consider the following compilable version of your example:
#include <memory>
#include <vector>
using namespace std;
class Surface
{
public:
void Gather(bool hit);
bool MouseOver;
};
enum class HitTestMode
{
Content = 1,
Foo = 3,
Bar = 4,
};
extern HitTestMode hittestmode;
bool anyMiceOver( vector<unique_ptr<Surface> > & Children, bool hit)
{
bool mouseOver = false;
for (unique_ptr<Surface>& child : Children)
{
child->Gather(hit);
if (hit && hittestmode == HitTestMode::Content && child->MouseOver && !mouseOver)
{
mouseOver = true;
}
}
return mouseOver;
}
When compiled using g++ 4.8.1 (mingw) with the -O3 optimization option, you get the following snippet of code for the loop (annotations added):
mov rbx, QWORD PTR [rcx] ; Children.begin()
mov rsi, QWORD PTR 8[rcx] ; Children.end()
cmp rbx, rsi
je .L8 ; early exit if Children is empty
test dl, dl ; hit == 0?
movzx edi, dl
je .L5 ; then goto loop L5
xor ebp, ebp
mov r12d, 1
jmp .L7
.p2align 4,,10
.L6:
add rbx, 8
cmp rsi, rbx ; check for end of Children
je .L2
.L7:
mov rcx, QWORD PTR [rbx]
mov edx, edi
call _ZN7Surface6GatherEb ; call child->Gather(hit)
cmp DWORD PTR hittestmode[rip], 1 ; check hittestmode
jne .L6
mov rax, QWORD PTR [rbx] ; check child->MouseOver
cmp BYTE PTR [rax], 0
cmovne ebp, r12d ; set mouseOver appropriately
jmp .L6
.p2align 4,,10
.L5: ; loop L5 is run only when hit == 0
mov rcx, QWORD PTR [rbx] ; get net element in Children
mov edx, edi
add rbx, 8
call _ZN7Surface6GatherEb ; call child->Gather(hit)
cmp rsi, rbx
jne .L5
.L8:
xor ebp, ebp
.L2:
mov eax, ebp
add rsp, 32
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
ret
You'll note that the check for hit has been hoisted out of the loop - and if it's false then the a loop that does nothing but call child->Gather() is run.
If hitmodetest is changed to be a variable that's passed as a function argument so it's no longer subject to possibly being changed by the call to child-Gather(hit), then the compiler will also hoist the check for the value of hittestmode out of the loop and jump to the loop that does nothing but call child->Gather().
With a local hittestmode using -O2 will calculate hit && hittestmode == HitTestMode::Content prior to the loop and stash that result in a register, but it will still test the register in each loop iteration instead of optimizing to a separate loops that don't even bother with the test.
Since you specifically asked about the VS2013 compiler (using /Ox and /Ot options), it doesn't seem to hoist or optimize either of the checks (for hit or hittestmode) out of the loop - all it seems to do is keep the values for those variable in registers.

In NASM, I want to compare an input keystroke based on its ASCII value

A simple program I am working on (for Homework) requires that I take a keystroke as input and return the categories it falls under (is it a printable charater, decimal, etc..)
I'm using cmp to compare the keystroke against the values of the maximum and/or minimum values in it's category (for example if the ASCII code of the keystroke is above 0x7F then it is a printable character)
However, there is obviously something not working in my comparison since no matter what, i.e. when I use the escape button as input, it is not printing "Control Key".
Could it be that keys need some more processing before they can be compared based on ASCII value?
Here is my code
segment .data
controlKey: db "Control Key", 10
controlLen: equ $-controlKey
printableKey: db "Printable", 10
printableLen: equ $-printableKey
decimalKey: db "Decimal", 10
decimalLen: equ $-decimalKey
segment .bss
key resb 2
segment .text
global main
main:
mov eax, 3 ; system call 3 to get input
mov ebx, 0 ; standart input device
mov ecx, key ; pointer to id
mov edx, 2 ; take in this many bytes
int 0x80
control: ; check if it's a control key
mov ebx, 31 ; highest control key
mov edx, key
cmp edx, ebx
jg printable
mov eax, 4
mov ebx, 1
mov ecx, controlKey
mov edx, controlLen
int 0x80
; jmp exit ; It's obviously not any of the other categories
printable: ; Tell that it's a printable symbol
mov eax, 4
mov ebx, 1
mov ecx, printableKey
mov edx, printableLen
int 0x80
decimal:
mov ebx, 30h ; smallest decimal ASCII
mov edx, key
cmp edx, ebx
jl uppercase
mov ebx, 39h ; test against 9
cmp edx, ebx
jg uppercase
mov eax, 4
mov ebx, 1
mov ecx, decimalKey
mov edx, decimalLen
int 0x80
uppercase:
lowercase:
mov eax, 4 ; system call 4 for output
mov ebx, 1 ; standard output device
mov ecx, key ; move the content into ecx
mov edx, 1 ; tell edx how many bytes
int 0x80 ;
exit:
mov eax, 1
xor ebx, ebx
int 0x80
The Escape key won't be read by your application, since it is - most probably - caught by the terminal that your application runs in. I can see that you're using the read syscall in your code, which is, of course, fine, but you should remember that this function only provides reading from a file descriptor, which doesn't necessarily have to contain all the control signals sent from the keyboard. The file descriptor (stdin) doesn't even have to come from the keyboard, since a file might be redirected to your process as standard input.
I don't know if there's a good way of achieving (capturing keystrokes, not the data that they represent - and this is what you're doing now) what you're trying to do just with system calls in Linux. You could try using some terminal controlling library, for example ncurses or termios, but I guess that isn't a part of your assignment.
I have done this a while back, here is a sample to show how to turn character echo on/off, and canonical mode on/off. When run, when you press a key, the keycode will be displayed on the screen, the program will exit once shift+q is pressed:
terminos.asm
ICANON equ 1<<1
ECHO equ 1<<3
sys_exit equ 1
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
global _start
SECTION .bss
lpBufIn resb 2
lpBufOut resb 2
termios resb 36
section .text
_start:
call echo_off
call canonical_off
.GetCode:
call GetKeyCode
movzx esi, byte[lpBufIn]
push esi
call PrintNum
pop esi
cmp esi, 81
jne .GetCode
call echo_on
call canonical_on
mov eax, sys_exit
xor ebx, ebx
int 80H
;~ #########################################
GetKeyCode:
mov eax, sys_read
mov ebx, stdin
mov ecx, lpBufIn
mov edx, 1
int 80h
ret
;~ #########################################
canonical_off:
call read_stdin_termios
; clear canonical bit in local mode flags
mov eax, ICANON
not eax
and [termios+12], eax
call write_stdin_termios
ret
;~ #########################################
echo_off:
call read_stdin_termios
; clear echo bit in local mode flags
mov eax, ECHO
not eax
and [termios+12], eax
call write_stdin_termios
ret
;~ #########################################
canonical_on:
call read_stdin_termios
; set canonical bit in local mode flags
or dword [termios+12], ICANON
call write_stdin_termios
ret
;~ #########################################
echo_on:
call read_stdin_termios
; set echo bit in local mode flags
or dword [termios+12], ECHO
call write_stdin_termios
ret
;~ #########################################
read_stdin_termios:
mov eax, 36h
mov ebx, stdin
mov ecx, 5401h
mov edx, termios
int 80h
ret
;~ #########################################
write_stdin_termios:
mov eax, 36h
mov ebx, stdin
mov ecx, 5402h
mov edx, termios
int 80h
ret
PrintNum:
push lpBufOut
push esi
call dwtoa
mov edi, lpBufOut
call GetStrlen
inc edx
mov ecx, lpBufOut
mov eax, sys_write
mov ebx, stdout
int 80H
ret
;~ #########################################
GetStrlen:
push ebx
xor ecx, ecx
not ecx
xor eax, eax
cld
repne scasb
mov byte [edi - 1], 10
not ecx
pop ebx
lea edx, [ecx - 1]
ret
;~ #########################################
dwtoa:
;~ number to convert = [ebp+8]
;~ pointer to buffer that receives number = [ebp+12]
push ebp
mov ebp, esp
push ebx
push esi
push edi
mov eax, [ebp + 8]
mov edi, [ebp + 12]
test eax, eax
jnz .sign
.zero:
mov word [edi], 30H
jmp .done
.sign:
jns .pos
mov byte [edi], "-"
neg eax
add edi, 1
.pos:
mov ecx, 3435973837
mov esi, edi
.doit:
mov ebx, eax
mul ecx
shr edx, 3
mov eax, edx
lea edx, [edx * 4 + edx]
add edx, edx
sub ebx, edx
add bl, "0"
mov [edi], bl
add edi, 1
cmp eax, 0
jg .doit
mov byte [edi], 0
.fixit:
sub edi, 1
mov al, [esi]
mov ah, [edi]
mov [edi], al
mov [esi], ah
add esi, 1
cmp esi, edi
jl .fixit
.done:
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4 * 2
makefile
APP = terminos
$(APP): $(APP).o
ld -o $(APP) $(APP).o
$(APP).o: $(APP).asm
nasm -f elf $(APP).asm