Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 1057625
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 16, 20262026-05-16T17:53:54+00:00 2026-05-16T17:53:54+00:00

I am trying to understand the assembly level code for a simple C program

  • 0

I am trying to understand the assembly level code for a simple C program by inspecting it with gdb’s disassembler.

Following is the C code:

#include <stdio.h>

void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
}

void main() {
  function(1,2,3);
}

Following is the disassembly code for both main and function

gdb) disass main
Dump of assembler code for function main:
0x08048428 <main+0>:    push   %ebp
0x08048429 <main+1>:    mov    %esp,%ebp
0x0804842b <main+3>:    and    $0xfffffff0,%esp
0x0804842e <main+6>:    sub    $0x10,%esp
0x08048431 <main+9>:    movl   $0x3,0x8(%esp)
0x08048439 <main+17>:   movl   $0x2,0x4(%esp)
0x08048441 <main+25>:   movl   $0x1,(%esp)
0x08048448 <main+32>:   call   0x8048404 <function>
0x0804844d <main+37>:   leave  
0x0804844e <main+38>:   ret
End of assembler dump.

(gdb) disass function
Dump of assembler code for function function:
0x08048404 <function+0>:    push   %ebp
0x08048405 <function+1>:    mov    %esp,%ebp
0x08048407 <function+3>:    sub    $0x28,%esp
0x0804840a <function+6>:    mov    %gs:0x14,%eax
0x08048410 <function+12>:   mov    %eax,-0xc(%ebp)
0x08048413 <function+15>:   xor    %eax,%eax
0x08048415 <function+17>:   mov    -0xc(%ebp),%eax
0x08048418 <function+20>:   xor    %gs:0x14,%eax
0x0804841f <function+27>:   je     0x8048426 <function+34>
0x08048421 <function+29>:   call   0x8048340 <__stack_chk_fail@plt>
0x08048426 <function+34>:   leave  
0x08048427 <function+35>:   ret    
End of assembler dump.

I am seeking answers for following things :

  1. how the addressing is working , I mean (main+0) , (main+1), (main+3)
  2. In the main, why is $0xfffffff0,%esp being used
  3. In the function, why is %gs:0x14,%eax , %eax,-0xc(%ebp) being used.
  4. If someone can explain , step by step happening, that will be greatly appreciated.
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-16T17:53:54+00:00Added an answer on May 16, 2026 at 5:53 pm

    The reason for the “strange” addresses such as main+0, main+1, main+3, main+6 and so on, is because each instruction takes up a variable number of bytes. For example:

    main+0: push %ebp
    

    is a one-byte instruction so the next instruction is at main+1. On the other hand,

    main+3: and $0xfffffff0,%esp
    

    is a three-byte instruction so the next instruction after that is at main+6.

    And, since you ask in the comments why movl seems to take a variable number of bytes, the explanation for that is as follows.

    Instruction length depends not only on the opcode (such as movl) but also the addressing modes for the operands as well (the things the opcode are operating on). I haven’t checked specifically for your code but I suspect the

    movl $0x1,(%esp)
    

    instruction is probably shorter because there’s no offset involved – it just uses esp as the address. Whereas something like:

    movl $0x2,0x4(%esp)
    

    requires everything that movl $0x1,(%esp) does, plus an extra byte for the offset 0x4.

    In fact, here’s a debug session showing what I mean:

    Microsoft Windows XP [Version 5.1.2600]
    (C) Copyright 1985-2001 Microsoft Corp.
    
    c:\pax> debug
    -a
    0B52:0100 mov word ptr [di],7
    0B52:0104 mov word ptr [di+2],8
    0B52:0109 mov word ptr [di+0],7
    0B52:010E
    -u100,10d
    0B52:0100 C7050700      MOV     WORD PTR [DI],0007
    0B52:0104 C745020800    MOV     WORD PTR [DI+02],0008
    0B52:0109 C745000700    MOV     WORD PTR [DI+00],0007
    -q
    c:\pax> _
    

    You can see that the second instruction with an offset is actually different to the first one without it. It’s one byte longer (5 bytes instead of 4, to hold the offset) and actually has a different encoding c745 instead of c705.

    You can also see that you can encode the first and third instruction in two different ways but they basically do the same thing.


    The and $0xfffffff0,%esp instruction is a way to force esp to be on a specific boundary. This is used to ensure proper alignment of variables. Many memory accesses on modern processors will be more efficient if they follow the alignment rules (such as a 4-byte value having to be aligned to a 4-byte boundary). Some modern processors will even raise a fault if you don’t follow these rules.

    After this instruction, you’re guaranteed that esp is both less than or equal to its previous value and aligned to a 16 byte boundary.


    The gs: prefix simply means to use the gs segment register to access memory rather than the default.

    The instruction mov %eax,-0xc(%ebp) means to take the contents of the ebp register, subtract 12 (0xc) and then put the value of eax into that memory location.


    Re the explanation of the code. Your function function is basically one big no-op. The assembly generated is limited to stack frame setup and teardown, along with some stack frame corruption checking which uses the afore-mentioned %gs:14 memory location.

    It loads the value from that location (probably something like 0xdeadbeef) into the stack frame, does its job, then checks the stack to ensure it hasn’t been corrupted.

    Its job, in this case, is nothing. So all you see is the function administration stuff.

    Stack set-up occurs between function+0 and function+12. Everything after that is setting up the return code in eax and tearing down the stack frame, including the corruption check.

    Similarly, main consist of stack frame set-up, pushing the parameters for function, calling function, tearing down the stack frame and exiting.

    Comments have been inserted into the code below:

    0x08048428 <main+0>:    push   %ebp                 ; save previous value.
    0x08048429 <main+1>:    mov    %esp,%ebp            ; create new stack frame.
    0x0804842b <main+3>:    and    $0xfffffff0,%esp     ; align to boundary.
    0x0804842e <main+6>:    sub    $0x10,%esp           ; make space on stack.
    
    0x08048431 <main+9>:    movl   $0x3,0x8(%esp)       ; push values for function.
    0x08048439 <main+17>:   movl   $0x2,0x4(%esp)
    0x08048441 <main+25>:   movl   $0x1,(%esp)
    0x08048448 <main+32>:   call   0x8048404 <function> ; and call it.
    
    0x0804844d <main+37>:   leave                       ; tear down frame.
    0x0804844e <main+38>:   ret                         ; and exit.
    
    0x08048404 <func+0>:    push   %ebp                 ; save previous value.
    0x08048405 <func+1>:    mov    %esp,%ebp            ; create new stack frame.
    0x08048407 <func+3>:    sub    $0x28,%esp           ; make space on stack.
    0x0804840a <func+6>:    mov    %gs:0x14,%eax        ; get sentinel value.
    0x08048410 <func+12>:   mov    %eax,-0xc(%ebp)      ; put on stack.
    
    0x08048413 <func+15>:   xor    %eax,%eax            ; set return code 0.
    
    0x08048415 <func+17>:   mov    -0xc(%ebp),%eax      ; get sentinel from stack.
    0x08048418 <func+20>:   xor    %gs:0x14,%eax        ; compare with actual.
    0x0804841f <func+27>:   je     <func+34>            ; jump if okay.
    0x08048421 <func+29>:   call   <_stk_chk_fl>        ; otherwise corrupted stack.
    0x08048426 <func+34>:   leave                       ; tear down frame.
    0x08048427 <func+35>:   ret                         ; and exit.
    

    I think the reason for the %gs:0x14 may be evident from above but, just in case, I’ll elaborate here.

    It uses this value (a sentinel) to put in the current stack frame so that, should something in the function do something silly like write 1024 bytes to a 20-byte array created on the stack or, in your case:

    char buffer1[5];
    strcpy (buffer1, "Hello there, my name is Pax.");
    

    then the sentinel will be overwritten and the check at the end of the function will detect that, calling the failure function to let you know, and then probably aborting so as to avoid any other problems.

    If it placed 0xdeadbeef onto the stack and this was changed to something else, then an xor with 0xdeadbeef would produce a non-zero value which is detected in the code with the je instruction.

    The relevant bit is paraphrased here:

              mov    %gs:0x14,%eax     ; get sentinel value.
              mov    %eax,-0xc(%ebp)   ; put on stack.
    
              ;; Weave your function
              ;;   magic here.
    
              mov    -0xc(%ebp),%eax   ; get sentinel back from stack.
              xor    %gs:0x14,%eax     ; compare with original value.
              je     stack_ok          ; zero/equal means no corruption.
              call   stack_bad         ; otherwise corrupted stack.
    stack_ok: leave                    ; tear down frame.
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have the following assembly code snippet I am trying to understand. It is
I am trying to understand this inline assembly code which comes from _hypercall0 here
I am trying to understand some assembly code and managed to finish most of
I am trying to understand the keil startup assembly code because it initializes the
I am trying to understand what the following code segment from tls.h in glibc
Trying to understand Ruby a bit better, I ran into this code surfing the
Trying to understand the math of this code snippet. A token is provided which
I am trying to understand how the assembly language works for a micro-computer architecture
Trying to understand how to link a function that is defined in a struct,
I'm trying to write a program in assembly and make the resulting executable as

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.