Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

207
Vistas
Manual Assembly vs GCC

Disclaimer: I'm just starting out with x86 assembly. I did learn a bit of SPIM at university, but that's hardly worth mentioning.

I thought I start with what's probably the most simple function in libc, abs(). Pretty straightforward in C:

long myAbs(long j) {
    return j < 0 ? -j : j;
}

My version in assembly:

    .global myAbs
    .type   myAbs, @function
    .text

myAbs:
    test %rdi, %rdi
    jns end
    negq %rdi
end:
    movq %rdi, %rax
    ret

(This doesn't work for 32bit integers, probably because RAX is a 64bit register and the sign is probably at the wrong position - I have to investigate that).

Now here's what gcc does (gcc -O2 -S myAbs.c):

        .file   "myAbs.c"
        .section        .text.unlikely,"ax",@progbits
.LCOLDB0:
        .text
.LHOTB0:
        .p2align 4,,15
        .globl  myAbs
        .type   myAbs, @function
myAbs:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $4144, %rsp
        orq     $0, (%rsp)
        addq    $4128, %rsp
        movq    %rdi, %rdx
        sarq    $63, %rdx
        movq    %fs:40, %rax
        movq    %rax, -8(%rbp)
        xorl    %eax, %eax
        movq    %rdi, %rax
        xorq    %rdx, %rax
        subq    %rdx, %rax
        movq    -8(%rbp), %rcx
        xorq    %fs:40, %rcx
        jne     .L5
        leave
        .cfi_remember_state
        .cfi_def_cfa 7, 8
        ret
.L5:
        .cfi_restore_state
        call    __stack_chk_fail@PLT
        .cfi_endproc
.LFE0:
        .size   myAbs, .-myAbs
        .section        .text.unlikely
.LCOLDE0:
        .text
.LHOTE0:
        .ident  "GCC: (Gentoo Hardened 5.1.0 p1.2, pie-0.6.3) 5.1.0"
        .section        .note.GNU-stack,"",@progbits

Why this big difference? GCC produces substantially more instructions. I can't imagine that this won't be slower than my code. Am I missing something? Or am I doing something seriousely wrong here?

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

For those who wonder what the generated code comes from, first note that when GCC compile myAbs with stack protection it transform it into this form

long myAbs(long j) {
    uintptr_t canary = __stack_chk_guard;

    register long result = j < 0 ? -j : j;

    if ( (canary = canary ^ __stack_chk_guard) != 0 )
        __stack_chk_fail();
}

The code to simply perform j < 0 ? -j : j; is

movq    %rdi, %rdx     ;RDX = j
movq    %rdi, %rax     ;RAX = j
sarq    $63, %rdx      ;RDX = 0 if j >=0, 0fff...ffh if j < 0
xorq    %rdx, %rax     ;Note: x xor 0ff...ffh = Not X, x xor 0 = x
                       ;RAX = j if j >=0, ~j if j < 0
subq    %rdx, %rax     ;Note: 0fff...ffh = -1
                       ;RAX = j+0 = j if j >= 0, ~j+1 = -j if j < 0
                       ;~j+1 = -j in two complement

Analyzing the generated code we get

    pushq   %rbp
    movq    %rsp, %rbp       ;Standard prologue

    subq    $4144, %rsp      ;Allocate slight more than 4 KiB     
    orq     $0, (%rsp)       ;Perform a useless RW operation to test if there is enough stack space for __stack_chk_fail

    addq    $4128, %rsp      ;This leave 16 byte allocated for local vars

    movq    %rdi, %rdx       ;See above
    sarq    $63, %rdx        ;See above

    movq    %fs:40, %rax     ;Get the canary
    movq    %rax, -8(%rbp)   ;Save it as a local var
    xorl    %eax, %eax       ;Clear it

    movq    %rdi, %rax       ;See above
    xorq    %rdx, %rax       ;See above
    subq    %rdx, %rax       ;See above

    movq    -8(%rbp), %rcx   ;RCX = Canary
    xorq    %fs:40, %rcx     ;Check if equal to the original value
    jne     .L5              ;If not fail

    leave
    ret
.L5:
    call    __stack_chk_fail@PLT  ;__stack_chk_fail is noreturn

So all the extra instructions are for implementing the Stack Smashing Protector.

Thanks to FUZxxl for pointing out the use of the first instructions after the prologue.

over 4 years ago · Santiago Trujillo Denunciar

0

Many of the beginning calls are to setup the stack and save the return address (something which you are not doing). Seems like theres are some stack protection going on. Perhaps you could tune your compiler settings to get rid of some overhead.

Perhaps adding flags to you compiler such as: -fno-stack-protector could minimise this difference.

Yes this probably is slower than your handwritten assembly, but offers much more protection and is probably worth the slight overhead.

As for why the stack protection still exists even though it is a leaf function see here.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda