Beginning pojos novice professional pdf


















In the following example, we look in the symbols table for every occurrence of the label start. We see the start addresses of section. We sort on the second column the memory addresses in reverse order. As you see, some basic knowledge of Linux commands comes in handy!

The start of the program is at some low address, and the start of main is at 0xa0. Look for the start of section. With readelf, we found that the executable code is at the lower side of memory. On top of the executable code, we have section. The stack in high memory can grow; it grows in the downward direction toward section. The available free memory between the stack and the other sections is called the heap.

The memory in section. Take note of the size of the executable, and then change, for example, the following: qvar resq 3 to the following: qvar resq 0 Rebuild the program and look again at the size of the executable.

Figure Output of readelf —symbols. Figure Memory map Why is it important to know about memory structure? It is important to know that the stack grows in the downward direction. When we exploit the stack later in this book, you will need this knowledge. Also, if you are into forensics or malware investigation, being able to analyze memory is an essential skill. We only touched on some basics here; if you want to know more, refer to the previously mentioned sources.

Floating-point arithmetic will be covered in a later chapter. Now is a good time to quickly review Chapter 2 on binary numbers. Starting with Integer Arithmetic Listing shows the example code we will analyze.

Before we investigate the arithmetic instructions, note that we use printf with more than two arguments, so we need an additional register: the first argument goes into rdi, the second into rsi, and the third into rdx. That is how printf expects us to provide the arguments in Linux. Here are some arithmetic instructions: The first instruction is add , which can be used to add signed or unsigned integers.

The second operand source is added to the first operand destination , and the result is placed in the first operand destination. The destination operand can be a register or a memory location. The source can be an immediate value, a register, or a memory location. The source and destination cannot be a memory location in the same instruction. When the resulting sum is too large to fit in the destination, the CF flag is set for signed integers.

For unsigned integers, the OF flag is then set. When the result is 0, the ZF flag is set to 1, and when the result is negative, the SF flag is set.

The subtraction with sub is similar to the add instruction. To increment a register or value in a memory location with 1, use the inc instruction. Similarly, dec can be used to decrement a register or value in a memory location with 1.

The arithmetic shift instructions are a special breed. The shift left, sal , is in fact multiplying; if you shift left one position, you are multiplying by 2. Every bit is shifted one place to the left, and a 0 is added to the right. Take the binary number 1. Shift left one place, and you obtain binary 10 or 2 in decimal representation. Shift left one place again, and you have binary or 4 in decimal representation. If you shift left two positions, you multiply by 4. What if you want to multiply by 6?

You shift left two times and then the add two times the original source, in that order. Shift right, sar , is similar to shift left, but it means dividing by 2.

Every bit is shifted one place to the right, and an additional bit is added to the left. Here there is a complication, however: if the original value was negative, the leftmost bit would be 1; if the shift instruction added a 0 bit at the left, the value would become positive, and the result would be wrong. So, in the case of a negative value, a sar will add a 1 bit to the left, and in the case of a positive value, 0 bits will be added to the left.

This is called sign extension. By the way, a quick way to see if a hexadecimal number is negative is to look at byte 7 the leftmost byte, counting from byte 0, which is the rightmost byte. But you need to take into account all 8 bytes. For example, 0xd12 is still a positive number because the leftmost byte, which is not shown, is a 0.

There are also nonarithmetic shift instructions; they will be discussed in Chapter Next, we multiply integers. For multiplying unsigned integers, you can use mul for unsigned multiplication and imul for signed multiplication. We will use imul, signed multiplication, which offers more flexibility: imul can take one, two, or three operands.

In our example, we use one operand; the operand following the imul instruction is multiplied with the value in rax. You may expect that the resulting product is stored in rax, but that is not entirely correct. When you multiply a bit digit with a bit digit, you will obtain a bit digit or a bit digit, and that value does not fit in a bit register.

To cope with this, the instruction imul will store the lower 64 bits of the resulting product in rax and the upper 64 bits in rdx. And this can be very deceptive! Modify number1 so that it contains and modify number2 so that it contains The product will just fit in rax; you can check that in SASM debug mode. Put a break before the imul instruction.

Restart debugging mode and step through the program. The result of the multiplication will be , as you can see in rax after the imul instruction is executed. Now modify number2 into Restart debugging. Look at rax after executing imul. You see that the product is a large negative number! That is because the most significant bit in rax is a 1 and SASM concludes that this must be a negative number. Also, printf thinks that rax contains a negative number because rax contains a 1 bit in the leftmost position, so it is assumed to be negative.

So, be careful with printf! We will dig somewhat deeper: as soon as the imul instruction is executed, rax contains 0xb14e9ff In binary, this is with a 1 in the most significant position and hence is negative. And rdx contains 0x6. That is with a 0 in the most significant position and hence is positive. The actual product is 0x6b14e9ff and can be found by combining rdx and rax, in this order: rdx:rax.

If you convert this hexadecimal number to decimal, you will find the product you expect: This is in fact the reverse of multiplication well, what did you expect? Divide the dividend in rdx:rax by the divisor in the source operand and store the integer result in rax. The modulo can be found in rdx. Here we just gave an overview that serves as a general introduction to integer arithmetic.

In the Intel manuals, not only will you find more details about the instructions, but you will find a large number of other arithmetic instructions that can be used in specific situations. Summary In this chapter, you learned the following: How to do integer arithmetic. How to do arithmetic shift left and shift right. Multiplication uses rax and rdx for storing the product.

Division uses rax and rdx for the dividend. Be careful when using printf when printing values. The Stack Jo Van Hoey1 1 Hamme, Belgium We have already discussed registers, the type of fast temporary storage that can be used to store values or addresses to be used during execution of instructions. There is also the slower storage, memory, where the processor can store values for a longer time. Then there is the stack, a contiguous array of memory locations.

Understanding the Stack As discussed in Chapter 8, the stack segment starts in high memory, and when it grows, it grows in the downward direction, like an icicle grows downward when it grows larger. Items are placed on the stack with the push instruction and removed from the stack with the pop instruction. Every time you push, the stack grows; every time you pop, the stack shrinks.

You can verify this stack behavior by monitoring rsp, the stack pointer, which points to the top thus actually the bottom, because it grows downward of the stack. The stack can be used as temporary storage to save values in registers and call them back later or, more importantly, to transfer values to functions.

Functions or procedures will be treated in detail later. In the example code in Listing , we will use the stack to reverse a string. Figure Reversing a string First, note that to calculate the string length, we decreased the length of the string by 1, ignoring the terminating 0.

Otherwise, the reversed string would start with a 0. Then the original string is displayed followed by a new line. The address of the string goes into rbx, and we will use a loop instruction , so we set rcx to the string length.

Then a loop is used to push character after character on the stack, starting with the first character. We move a character byte into al. Then we push rax onto the stack. Every time you use push, 8 bytes are moved to the stack. If we did not initialize rax before, it might well be that rax contains values in the upper bytes, and pushing these values to the stack may not be what we want.

After that, the stack contains the pushed character plus the additional 0 bits in the bits above al. Another loop is started that pops character after character from the stack and stores them in memory in the original string, one after another. Note that we only want 1 byte, so we pop to rax and only use al. Here is an overview of what is happening see Figure : the original string is at the right, and the characters are pushed, sent one by one to the stack, where they are appended to the previous stack content.

Figure Schema of reversing a string Somehow you have to keep track of what you pushed on the stack and in what order. For example, when you use the stack to temporarily store registers, be sure to pop the registers in the reverse correct order; otherwise, your program will be wrong or in the worst case will probably crash. You can pop to a register or a memory location but not to an immediate value, which is quite evident.

If you want to push and pop the flag register to the stack, you can use the instructions pushf and use popf. Keeping Track of the Stack So, keeping track of the stack is important, and our old friend DDD has some easy features to do that. First open your editor to the source and delete the debug line that SASM added; then save the file and quit. Set a breakpoint at, for example, main: and then click Run in the floating panel. Now start debugging and step through the program with the Next button you do not want to step line per line through the printf function.

See how the stack is displayed and updated in the upper window. Do not worry about the initial stuff that is displayed. When you arrive at the instruction after the push instruction, you will see that characters are pushed onto the stack in ASCII decimal representation 41, 42, etc. Watch how the stack decreases during the second loop.

That is an easy way to see what is on the stack and in what order. Figure shows how it looks. There is no guarantee that it will continue working as expected in the future, but for now it is not very elegant, but it will do. In all fairness, you could force SASM to show the stack also, but that requires more manual work. Here is how it works: remember that you can show memory variables during debugging in SASM, and the stack is just a list of memory locations, with rsp pointing to the lowest location.

Thus, we have to convince SASM to show us what is at address rsp and at the memory locations above. Figure shows an example memory window in SASM showing the stack.

As Type, we specified Char, bytes, 8 bytes, and Address. We chose Characters because we are pushing a string and then it is easy to read for us, and we chose bytes, because we are interested in byte values al contains 1 byte every time , so 8 bytes are pushed every time.

And rsp contains an Address. Step through the program and see how the stack changes. Summary In this chapter, you learned the following: The stack starts at an address in high memory and grows to lower addresses. Push decreases the stack pointer rsp.

Pop increases the stack pointer rsp. Push and pop work in reverse order. How to use DDD to examine the stack. How to use SASM to examine the stack. Floating-Point Arithmetic Jo Van Hoey1 1 Hamme, Belgium You already know about integer arithmetic; now we will introduce some floating-point computations. There is nothing difficult here; a floating-point value has a decimal point in it and zero or more decimals. We have two kinds of floating-point numbers: single precision and double precision.

Double precision is more accurate because it can handle more significant digits. With that information, you now know enough to run and analyze the sample program in this chapter. Single vs. Double Precision For those more curious, here is the story.

A single-precision number is stored in 32 bits: 1 sign bit, 8 exponent bits, and 23 fraction bits. When the number is positive, it is 0; when the number is negative, the sign bit is 1. The exponent bits are more complicated. To make that distinction clear, in the case of single precision, is added to a positive exponent before storing it. That means a zero exponent would be stored as That is called a bias. With double-precision values, the bias is In the example above, the 1.

Here is a simple example to show how it works. Sign bit 0, because the number is positive. Obtain a number in the format b. The leading 1 will not be stored. Hence, the exponent is 3 because we moved the point three places. We add because the exponent is positive, so we obtain , which in binary is Note that the hexadecimal representation of the same value is different in single precision than in double precision. Why not always use double precision and benefit from the higher precision?

Double-precision calculations are slower than single-precision calculations, and the operands use more memory. If you think this is complicated, you are right. Find an appropriate tool on the Internet to do or at least verify the conversions. You can encounter bit floating-point numbers in older programs, and these numbers have their own instructions, called FPU instructions. This functionality is a legacy from the past and should not be used in new developments.

But you will find FPU instructions in articles on the Internet from time to time. Coding with Floating-Point Numbers Listing shows the example program. Use a debugger to step through the program and investigate the registers and memory. Note, for example, how 9. Remember that when debugging in SASM, the xmm registers are at the bottom of the register window, in the leftmost part of the ymm registers. Similarly, there are addss , subss , mulss , divss , and sqrtss instructions.

The rest should be pretty straightforward by now! Figure fcalc. Make and run the program and see what happens: program crash! The cause for the crash will become clear later, but it has to do with stack alignment. Modern high-level programming languages have structures such as do…while, while…do, case, and so on.

This is not so with assembly language. But similar to modern program languages, assembly language has functions and procedures to help you give your code more structure. A little bit of nit-picking: a function executes instructions and returns a value. A procedure executes instructions and does not return a value. In this book, we have already used functions; that is, we used an external function called printf , which is a C library function.

In this chapter, we will introduce simple functions; in later chapters, we will cover important aspects of functions such as stack alignment, external functions, and calling conventions. Writing a Simple Function Listing shows an example of an assembler program with a simple function to calculate the area of a circle.

Figure function. In main, the function area is called, which calculates the area of a circle using radius and pi, which are variables stored in a location in memory. As you can see, functions must have a prologue and an epilogue, similar to main. The computed area is stored in xmm0. Returning from the function to main, printf is called with rax containing the value 1, meaning there is one xmm register that needs to be printed. We introduce a new instruction here: leave.

This instruction does the same as mov rsp, rbp, and pop rbp the epilogue. If you return a value from a function, you use xmm0 for floating-point values and use rax for other values, such as integers or addresses. The function arguments, pi and radius, are located in memory. That is okay for now, but it is better to use registers and the stack to store function arguments. So, functions can call other functions. In fact, main is just a function calling other functions.

But beware that functions cannot be nested, which means functions cannot contain the code for other functions. Also, functions can have their own sections, such as. What about the period before pi and the fmt variables? The period indicates a local variable, which means that the variable is known only inside the function where it is declared.

In the function area, we used a value for pi that is different from the pi used in the function circum. The variable radius, declared in section. It is always advisable to use local variables whenever possible; this reduces the risk of conflicting variable names. Figure shows the output for the program. Figure function2. Functions can have their own section. Functions cannot be nested. Functions can call other functions. How to use local variables. That 8-byte address is the address of the instruction to be executed after the function.

So, when the function ends, the program execution will find the return address from the stack and continue operation after the function call. Inside the function, we can also use the stack for different purposes. Every time you push something on the stack, the stack pointer will decrease by 8 bytes, and every time you pop something from the stack, the stack pointer will increase by 8 bytes.

Otherwise, the executing program would have a wrong address for the instruction to be executed after the function call. Stack Alignment In the Intel manuals, you will find mention of a requirement that the stack has to have a byte alignment when you call a function.

This may sound a bit weird, as the stack is built in 8-byte or bit memory. The reason is that there are SIMD instructions that perform parallel operations on larger blocks of data, and these SIMD instructions may require that these data are located in memory on addresses that are multiples of 16 bytes.

In previous examples, when we used printf with xmm registers, we aligned the stack on 16 bytes, without explicitly telling you. Go back to Chapter 11 on floating-point arithmetic, where we crashed the program by commenting out push rbp and pop rbp. The program crashed because deleting these instructions caused the stack to be not aligned.

If you use printf without xmm registers, you can get away without stack alignment, but if you do that, bugs are going to bite you someday. For now, keep in mind that when you call a function, you need to align the stack on an address that is a multiple of 16 bytes.

As far as the processor is concerned, main is just another function. Before your program starts execution, the stack is aligned. Just before main starts, an 8-byte return address is pushed onto the stack, which means the stack is not aligned upon the start of main. If the stack is not touched between the start of main and the call of a function, the stack pointer rsp is not byte aligned. You can verify that by looking at rsp: if rsp ends with 0, it is bit aligned. To make it zero, you push something onto the stack so that it becomes bit aligned.

Of course, do not forget the corresponding pop instruction later. This alignment requirement is one of the reasons for using a prologue and an epilogue. The first instruction in main and in a function should push something onto the stack to align it.

The rbp register is also called the base pointer. Why are we using rbp? In the prologue, when using stack frames explained later , rbp is modified, so before rbp is used in a stack frame, it is pushed onto the stack to preserve it when returning.

Even when not building a stack frame, rbp is the ideal candidate to align the stack because it is not used for argument passing to a function. Argument passing will be discussed later in the chapter. In the prologue, we also use the instruction mov rbp,rsp. This instruction preserves rsp, which is our stack pointer containing the return address. The prologue instructions are reversed in the epilogue; needless to say, it is best to not meddle with rbp!

In future chapters, you will see a number of other methods to align the stack. Listing shows some source code to play with. Keep an eye on rsp when debugging and stepping through the program with SASM. Comment out push rbp and pop rbp and see what happens.

If the program execution arrives at printf with an unaligned stack, the program will crash. That is because printf definitely requires alignment. In this program, we do not use complete prologues and epilogues; that is, we do not build stack frames.

We only use push and pop to illustrate alignment. Pure luck! You'll learn how to build a complete enterprise Java-based web application from scratch, and how to integrate the different open source frameworks to achieve this goal. You'll also learn techniques for rapidly developing such applications. Skip to main content Skip to table of contents.

Advertisement Hide. This service is more advanced with JavaScript available. Authors Brian Sam-Bodden. Dreamweaver CS5. Essential angular for ASP. Essential Docker for ASP. Expert ASP. Front-end Development with ASP. Front-End Fundamentals: A practical guide to front-end web development. Js, Node. Full Stack Web Development with Backbone. Full stack web development with Backbone.

Get Programming with F : A guide for. Getting Started with Meteor. Getting Started with OAuth 2. Physical description xix, p. Series Expert's voice in Java. Online Available online. Ebook Central Full view. Report a connection problem. More options. Find it at other libraries via WorldCat Limited preview. Contributor ProQuest Firm.



0コメント

  • 1000 / 1000