Reading a flag from program C

For the sake of curiosity, I try to read the flag register and print it beautifully.

I tried reading it with gcc asm , but I can't get it to work. Any clues on how to do this? I am running Intel Core 2 Duo and Mac OS X. The following code is what I have. I was hoping this would tell me if an overflow occurred:

#include <stdio.h>

int main (void){
  int a=10, b=0, bold=0;
  printf("%d\n",b);
  while(1){
    a++;
  __asm__ ("pushf\n\t"
   "movl 4(%%esp), %%eax\n\t"
   "movl %%eax , %0\n\t"
   :"=r"(b)      
   :         
   :"%eax"        
   ); 
  if(b!=bold){ 
    printf("register changed \n %d\t to\t %d",bold , b);
  }
  bold = b;
  }
}

This gives a segmentation error. When I run gdb, I get the following:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x000000005fbfee5c
0x0000000100000eaf in main () at asm.c:9
9       asm ("pushf \n\t"
+6
source share
6 answers

PUSHF/PUSHFD/PUSHFQ ( . http://siyobik.info/main/reference/instruction/PUSHF%2FPUSHFD), . C. ( ) .

( , , JO (jump if set) JNO (, ), - № 11 ( 0))

EFLAGS: http://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture#EFLAGS_Register

Visual C ( wham-bam/some jumps to debug flow), GCC:

int test2 = 2147483647; // max 32-bit signed int (0x7fffffff)
unsigned int flags_w_overflow, flags_wo_overflow;
__asm
{
    mov ebx, test2 // ebx = test value

    // test for no overflow
    xor eax, eax // eax = 0
    add eax, ebx // add ebx
    jno no_overflow // jump if no overflow

testoverflow:
    // test for overflow
    xor ecx, ecx // ecx = 0
    inc ecx // ecx = 1
    add ecx, ebx // overflow!
    pushfd // store flags (32 bits)
    jo overflow // jump if overflow
    jmp done // jump if not overflown :(

no_overflow:
    pushfd // store flags (32 bits)
    pop edx // edx = flags w/o overflow
    jmp testoverflow // back to next test

overflow:
    jmp done // yeah we're done here :)

done:
    pop eax // eax = flags w/overflow
    mov flags_w_overflow, eax // store
    mov flags_wo_overflow, edx // store
}

if (flags_w_overflow & (1 << 11)) __asm int 0x3 // overflow bit set correctly
if (flags_wo_overflow & (1 << 11)) __asm int 0x3 // overflow bit set incorrectly

return 0;
+5

, lahf . , . a, .

, + check , C.

, lahf ah (8 ) eflags, . pushf; pop %eax.

:

#include <stdio.h>

int main (void){
    int a=2147483640, b=0, bold=0;
    printf("%d\n",b);
    while(1){
            a++;
            __asm__ __volatile__ ("pushf \n\t"
                            "pop %%eax\n\t"
                            "movl %%eax, %0\n\t"
                            :"=r"(b)
                            :
                            :"%eax"
                    );
            if((b & 0x800) != (bold & 0x800)){
                    printf("register changed \n %x\t to\t %x\n",bold , b);
            }
            bold = b;
    }
}


$ gcc -Wall  -o ex2 ex2.c
$ ./ex2  # Works by sheer luck
0
register changed
 200206  to      200a96
register changed
 200a96  to      200282

$ gcc -Wall -O -o ex2 ex2.c
$ ./ex2  # Doesn't work, the compiler hasn't even optimized yet!
0
+5

XY. , ,

, , 127 127, 8- . 127 + 127 - 254, 8- 1111 1110 , -2 , , . ( ) . , . , , ( ) ( ). , ( ).

, . , , "" , .

https://en.wikipedia.org/wiki/Overflow_flag

, C

int add(int a, int b, int* overflowed)
{
    // do an unsigned addition since to prevent UB due to signed overflow
    unsigned int r = (unsigned int)a + (unsigned int)b;

    // if a and b have the same sign and the result sign is different from a and b
    // then the addition was overflowed
    *overflowed = !!((~(a ^ b) & (a ^ r)) & 0x80000000);
    return (int)r;
}

, , , x86. . RISC, MIPS RISC-V, , /

, __builtin_add_overflow Clang GCC. , . , ARM

add     w3, w0, w1  # r = a + b
eon     w0, w0, w1  # a = a ^ ~b
eor     w1, w3, w1  # b = b ^ r
str     w3, [x2]    # store sum ([x2] = r)
and     w0, w1, w0  # a = a & b = (a ^ ~b) & (b ^ r)
lsr     w0, w0, 31  # overflowed = a >> 31
ret

,


int

unsigned int a, b, result = a + b;
int overflowed = (result < a);
+3

, , , , , , . :

pushf
pop %0

add $4,%%esp asm, , .

+2

, GCC a++, , .

a () , GCC lea, inc add, mov [CN00 ].

, , gcc , .

a++; asm(...) a++; asm(...)

, . asm, add inc asm, . , SETCC, , seto %0, 8- . GCC6, , OF FLAGS .

, a++ C - , a++ . , - , a - , gcc, , 64-, -.

GCC , gcc5

/ add, sub mul, . GCC, UB , .

  • bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
  • bool __builtin_sadd_overflow (int a, int b, int *res) - int
  • bool __builtin_saddll_overflow (long long int a, long long int b, long long int *res) - 64- long long .

, , , , ..

saddl , long . ( x86-64 gcc int 32-, long long 64-, long Windows Windows. , AVR, int 16-, long 32-).

int checked_add_int(int a, int b, bool *of) {
    int result;
    *of = __builtin_sadd_overflow(a, b, &result);
    return result;
}

gcc -O3 x86-64 System V asm, int overflows(int+a, int+b) {%0a++ +bool+of = __builtin_add_overflow_p(a,+b, (int)0);%0a++ return of; } int+Checked_add_int(int+a, int+b,+bool+*of) {%0a++ int result;%0a++ *of = __builtin_sadd_overflow(a,+b, &result);%0a++ return result; } #include #include int main( int+argc,+Char+**argv+) {%0a++if(+argc+< 3 ) {%0a++ printf( "Usage: %25s+\n", *argv+);%0a++ return 0;%0a++}%0a++int+a;%0A++bool+of = __builtin_sadd_overflow(atoi(argv[1]),+atoi(argv[2]), &a);%0a++printf("%d overflowed%3F+%d\n",+a, of); } '),l:'5',n:'0',o:'C++ source #1',t:'0')),k:31.79650238473768,l:'4',m:100,n:'0',o:'',s:0,t:'0'),(g:!((g:!((h:compiler,i:(compiler:g91,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),lang:c++,libs:!(),options:'-xc -O3 -Wall',source:1),l:'5',n:'0',o:'x86-64 gcc 9.1+(Editor #1,+Compiler+#1)+C++',t:'0')),header:(),k:50,l:'4',m:50,n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:icc191,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'1',trim:'1'),lang:c++,libs:!(),options:'-xc -O3 -Wall',source:1),l:'5',n:'0',o:'x86-64 icc 19.0.1+(Editor #1,+Compiler+#2)+C++',t:'0')),header:(),k:50,l:'4',n:'0',o:'',s:0,t:'0')),k:68.20349761526232,l:'2',m:100,n:'0',o:'',t:'0')),l:'2',n:'0',o:'',t:'0')),version:4 rel="nofollow noreferrer"> Godbolt

checked_add_int:
        mov     eax, edi
        add     eax, esi             # can't use the normal lea eax, [rdi+rsi]
        seto    BYTE PTR [rdx]
        and     BYTE PTR [rdx], 1    # silly compiler, it already 0/1
        ret

ICC19 setcc , , , , .

, if(of) {} jo jno setcc 0/1; , .


, gcc7, ( ) .

#include <stdbool.h>
int overflows(int a, int b) {
    bool of = __builtin_add_overflow_p(a, b, (int)0);
    return of;
}

gcc -O3 x86-64 System V asm, Godbolt

overflows:
        xor     eax, eax
        add     edi, esi
        seto    al
        ret

. C/C++

+2

The following C program will read the FLAGS register when compiling with GCC and any x86 or x86_64 computer in accordance with a calling convention in which integers are returned in %eax. You may need to pass an argument to the -zexecstackcompiler.

#include<stdio.h>
#include<stdlib.h>

int(*f)()=(void*)L"\xc3589c";

int main( int argc, char **argv ) {
  if( argc < 3 ) {
    printf( "Usage: %s <augend> <addend>\n", *argv );
    return 0;
  }
  int a=atoi(argv[1])+atoi(argv[2]);
  int b=f();
  printf("%d CF %d PF %d AF %d ZF %d SF %d TF %d IF %d DF %d OF %d IOPL %d NT %d RF %d VM %d AC %d VIF %d VIP %d ID %d\n", a, b&1, b/4&1, b>>4&1, b>>6&1, b>>7&1, b>>8&1, b>>9&1, b>>10&1, b>>11&1, b>>12&3, b>>14&1, b>>16&1, b>>17&1, b>>18&1, b>>19&1, b>>20&1, b>>21&1 );
}

Try it online!

A funny looking string literal parses into

0x0000000000000000:  9C    pushfq 
0x0000000000000001:  58    pop    rax
0x0000000000000002:  C3    ret    
0
source

All Articles