Showing posts with label compilers. Show all posts
Showing posts with label compilers. Show all posts

Monday, November 12, 2012

Building GCC: configure option to pass CFLAGS into generated Makefiles? (the Monkey Speaks)



I am hoping I can use "configure --enable..." below to pass one of the CFLAGS mentioned here into the generated Makefiles that are used when I build gcc, so I can have a copy of gcc that contains the intermediate assembly source...  (Why? It's complicated).


I do not mind script-hacking Makefiles directly, which I have done before, but somehow it seems like it may the wrong way. (?) 





Sometimes, I think that GCC is the monolith, and I am a monkey, with some bones...





-save-temps=obj , -save-temps=cwd, & other optimizations from GCC 4.5 General Optimizer Improvements




--enable-cxx-flags=FLAGS


With this option, you can pass a string of -f (functionality) flags to the compiler to use when building libstdc++. This option can change the library ABI. FLAGS is a quoted string of options, like
--enable-cxx-flags='-fvtable-gc -fomit-frame-pointer -ansi'
Note that the flags don't necessarily have to all be -f flags, as shown, but usually those are the ones that will make sense for experimentation and configure-time overriding.
The advantage of --enable-cxx-flags over setting CXXFLAGS in the 'make' environment is that, if files are automatically rebuilt, the same flags will be used when compiling those files as well, so that everything matches.


Fun with GCC: Configure

'via Blog this'

Why a gcc build creates so many temporary files [LinuxForums]

Quote Originally Posted by hazel View Post
I've just done the first deep update of my system. To my surprise and satisfaction, it recompiled specifically for my machine quite a few packages that had originally come with the stage 3 tarball, including gcc. I was also impressed by the messages that portage gave me, explaining exactly what tidying up operations would be necessary afterwards.

While gcc was compiling, I monitored the number of files the build was creating by using df -i periodically (I already knew it was a large number). The number of inodes consumed was about 55 thousand! That is grotesque! What kind of a process needs 55,000 files? I know that the compiler must create an object file for each source file but were there really 27,000 source files in this package? Just what is going on here?
gcc is a huge piece of software. It is not just a C compiler, it can do much more. It understands a number of languages, not just C, and is also a cross compiler. It can compile for a huge number of architectures.

The source package contains more than 10,000 .c files, and a total amount of +60,000 files, add to that the intermediate files and you can start realizing the magnitudes we are talking about.

I found it interesting...  Cheers, Connie

Code:
$ tar xf /var/portage/distfiles/gcc-4.3.3.tar.bz2 
$ find gcc-4.3.3/ -name \*.c|wc -l
11926
$ find gcc-4.3.3/ -name \*|wc -l
61659
Makefiles will be created when the configure script is run, and a lot of intermediate object files will be created as you say while compiling. Oh! and don't forget that gcc automatically bootstraps itself. That means that each time you emerge gcc, this happens:

  • first, gcc is compiled using whatever compiler you have on your system
  • second, gcc is re-compiled using the gcc version that you just compiled
  • third, gcc is recompiled again using the gcc produced on the second step, then both are compared (the third and the second) to see if they are 1:1 the same and ensure that there's no problem.


Now you can start wondering how the number of intermediate files is really huge.

And don't forget that in amd64 if you have multilib enabled two entire compilers are created for 32 and 64 bits, that means that gcc will be recompiled 6 times, and will double the total number of files once again.

Why does a build create so many temporary files?

'via Blog this'

Thursday, August 30, 2012

Parallel Compilation Technical Lead opportunity | Panève

Since it does not say, I will note that the position is to be staffed in Boulder, Colorado! (a great place to live).  The "Apply" link hooks up to the corporate website; alternatively, if you know me via one of my esteemed former coworkers at Bell Labs, HP, or Cadence, please feel free to supply a resume separately or in addition via email for me to "expedite", along with who you know that I also know.
Cheers,
Connie

Parallel Compilation Technical LeadAPPLY

We are currently seeking an experienced Parallel Compilation Technical Lead with expertise in porting GCC and LLVM to a parallel architecture. The candidate should have experience with auto-parallelization, auto-vectorization and a thread parallel runtime. The person will have proficiency in C and C++ combined with good problem solving and collaborative skills, and the ability to work independently in a dynamic and fast paced environment. This is a full-time position.
Responsibilities:
  • Technical lead to port/enhance GCC and LLVM to a new advanced scalable thread parallel architecture
  • Push state of the art for auto-parallelization
  • Performance analysis and optimization of single thread and parallel execution
  • Development of assemblers, linkers and other development tools
  • Work as an integral part of the team to develop, verify and deliver working solutions
  • Participate in the entire development lifecycle of the software stack including specification, design, implementation and test
  • Reproduce and resolve issues
  • Identify and create benchmarks and other tools used to measure compiler performance and efficiency
Qualifications:
  • Masters degree in Computer Science or Engineering
  • Minimum 5 years experience
  • Ideal candidate will have experience with porting LLVM and/or GCC.
  • Background in compiler architecture, optimization, code generation and overall design of compilers
  • Knowledge of auto-parallelization, auto-vectorization, thread parallel runtime
  • Experience with developing compilers for embedded devices
  • Knowledge of embedded architectures, instruction sets, and development tools
  • Experience developing assemblers, linkers, and other low level tools
  • Familiarity with analyzing generated code for optimization/code generation opportunities.
  • Excellent written, oral communication and time management skills
  • Ability to work independently, as well as with a team

Join Panève | Panève:

'via Blog this'

Friday, July 20, 2012

-save-temps=obj , -save-temps=cwd, & other optimizations from GCC 4.5 General Optimizer Improvements

GCC 4.5 Release Series — Changes, New Features, and Fixes - GNU Project - Free Software Foundation (FSF):


General Optimizer Improvements

  • The -save-temps now takes an optional argument. The -save-temps and -save-temps=cwd switches write the temporary files in the current working directory based on the original source file. The -save-temps=obj switch will write files into the directory specified with the -o option, and the intermediate filenames are based on the output file. This will allow the user to get the compiler intermediate files when doing parallel builds without two builds of the same filename located in different directories from interfering with each other.
  • Debugging dumps are now created in the same directory as the object file rather than in the current working directory. This allows the user to get debugging dumps when doing parallel builds without two builds of the same filename interfering with each other.
  • GCC has been integrated with the MPC library. This allows GCC to evaluate complex arithmetic at compile time more accurately. It also allows GCC to evaluate calls to complex built-in math functions having constant arguments and replace them at compile time with their mathematically equivalent results. In doing so, GCC can generate correct results regardless of the math library implementation or floating point precision of the host platform. This also allows GCC to generate identical results regardless of whether one compiles in native or cross-compile configurations to a particular target. The following built-in functions take advantage of this new capability: cacos, cacosh, casin, casinh, catan, catanh, ccos, ccosh, cexp, clog, cpow, csin, csinh, csqrt, ctan, and ctanh. Thefloat and long double variants of these functions (e.g. csinf and csinl) are also handled.
  • A new link-time optimizer has been added (-flto). When this option is used, GCC generates a bytecode representation of each input file and writes it to specially-named sections in each object file. When the object files are linked together, all the function bodies are read from these named sections and instantiated as if they had been part of the same translation unit. This enables interprocedural optimizations to work across different files (and even different languages), potentially improving the performance of the generated code. To use the link-timer optimizer, -flto needs to be specified at compile time and during the final link. If the program does not require any symbols to be exported, it is possible to combine -flto and the experimental -fwhopr with -fwhole-program to allow the interprocedural optimizers to use more aggressive assumptions.
  • The automatic parallelization pass was enhanced to support parallelization of outer loops.
  • Automatic parallelization can be enabled as part of Graphite. In addition to -ftree-parallelize-loops=, specify -floop-parallelize-all to enable the Graphite-based optimization.
  • The infrastructure for optimizing based on restrict qualified pointers has been rewritten and should result in code generation improvements. Optimizations based on restrict qualified pointers are now also available when using -fno-strict-aliasing.
  • There is a new optimization pass that attempts to change prototype of functions to avoid unused parameters, pass only relevant parts of structures and turn arguments passed by reference to arguments passed by value when possible. It is enabled by -O2 and above as well as -Os and can be manually invoked using the new command-line switch -fipa-sra.
  • GCC now optimize exception handling code. In particular cleanup regions that are proved to not have any effect are optimized out.

'via Blog this'

Thursday, July 19, 2012

Programmer's search/when your normal wildcard search isn't cutting it!

-save-temps= - SymbolHound Search:

Such a very handy website...  I am a big fan of Google search, but this works so much better than Google for programming stuff of this type (I gather that is a conscious decision that Google made, just business, not personal).



3 results found for -save-temps=
another "trick" to keep going with a single compile-and-link step would be to add -save-temps=obj to your g++ command line so that 4 Remove
http://stackoverflow.com/question...g-c0x-programs-in-macports-gcc-4-5
using different source and output directories. gcc -save-temps=obj -c dir1/foo.c -o dir1/foo.o gcc -save-temps=obj -c dir2/foo.c -o dir2/foo.o The
http://stackoverflow.com/question...rmediate-files-in-current-director
Improvements The -save-temps now takes an optional argument. The -save-temps and -save-temps=cwd switches write the temporary files in the current working
http://www.gnu.org/software/gcc/gcc-4.5/changes.html


'via Blog this'

Tuesday, July 10, 2012

The ELF Object File Format by Dissection | Linux Journal

The ELF Object File Format by Dissection | Linux Journal:


The ELF Object File Format by Dissection

 in
The Executable and Linking Format has been a popular topic lately, as people ask why the kernel configuration script asks whether or not to configure loading ELF executables. Since ELF will eventually be the common object file format for Linux binaries, it is appropriate to document it a bit. Last month, Eric introduced us to ELF, and this month, he gives us a guided tour of real ELF files.
Last month, we reached a point where were beginning to dissect some real ELF files. For this, I will use the readelfutility which I wrote when I was first trying to understand the ELF format itself. Later on, it became a valuable tool for debugging the linker as I added support for ELF. The sources to readelf should be on tsx-11.mit.edu in pub/linux/packages/GCC/src or in pub/linux/BETA/ibcs2.
Let us start with a very simple program—the hello world program we used last month.
largo% cat hello.c
main()
{
        printf("Hello World\n");
}
largo% gcc-elf -c hello.c
On my laptop, the gcc-elf command invokes the ELF version of gcc—once ELF becomes the default format, you will be able to use the regular gcc command which produces the ELF file hello.o. Each ELF file starts with a header (struct elfhdr in /usr/include/linux/elf.h), and the readelf utility can display the contents of all of the fields:
largo% readelf -h hello.o
ELF magic:7f 45 4c 46 01 01 01 00 00 00 00 00
        00 00 00 00
Type, machine, version = 1 3 1
Entry, phoff, shoff, flags = 0 0 440 0
ehsize, phentsize, phnum = 52 0 0
shentsize, shnum, shstrndx = 40 11 8
The ELF magic field is just a way of unambiguously identifying this as an ELF file. If a file does not contain those 16 bytes in the magic field, it is not an ELF file. The type, machine, and version fields identify this as an ET_REL file (i.e., an object file) for the i386. The ehsize field is just the sizeof(struct elfhdr).
Each ELF file contains a table that describes the sections within the file. The shnumfield indicates that there are 11 sections; the shoff field indicates that the section header table starts at byte offset 440 within the file. The shentsize field indicates that the entry for each section is 40 bytes long. All throughout ELF, the sizes of various structures are always explicitly stated. This allows for flexibility; the structures can be expanded as required for some hardware platforms and the standard ELF tools do not have to know about this to be able to make sense of the binary. Also, it allows room for future expansion of the structures by newer versions of the standard.
largo% readelf -S hello.o
There are 11 section headers, starting at offset 1b8:
[0]             NULL            00000000 00000 00000 00 / 0 0 0 0
[1] .text       PROGBITS        00000000 00040 00014 00 / 6 0 0 10
[2] .rel.text   REL             00000000 00370 00010 08 / 0 9 1 4
[3] .data       PROGBITS        00000000 00054 00000 00 / 3 0 0 4
[4] .bss        NOBITS          00000000 00054 00000 00 / 3 0 0 4
[5] .note       NOTE            00000000 00054 00014 00 / 0 0 0 1
[6] .rodata     PROGBITS        00000000 00068 0000d 00 / 2 0 0 1
[7] .comment    PROGBITS        00000000 00075 00012 00 / 0 0 0 1
[8] .shstrtab   STRTAB          00000000 00087 0004d 00 / 0 0 0 1
[9] .symtab     SYMTAB          00000000 000d4 000c0 10 / 0 a a 4
[a] .strtab     STRTAB          00000000 00194 00024 00 / 0 0 0 1
Listing 1. Section Table for hello.o
Each section header is just a struct ELF32_Shdr. You may notice that the name field is just a number—this is not a pointer, but an offset into the .shstrtab section (we can find the index of the .shstrtab section from the file header in the shstrndx field). Thus we find the name of each section at the specified offset within the .shstrtab section. Let us dump the section table for this file; see figure 1. You will notice sections for nearly everything which we have already discussed. Each section has an identifier which specifies what the section contains (in general, you should never have to actually know the name of a section or compare it to anything).
After the type, there is a series of numbers. The first of these is the address in virtual memory where this section should be loaded. Since this is a .o file, it is not intended to be loaded into virtual memory, and this field is not filled in. Next is the offset within the file of the section, and then is the size of the section. After this come a series of numbers—I won't parse these in detail for you, but they contain things like the required alignment of the section, a set of flags which indicate whether the section is read-only, writable, and/or executable.
The readelf program is capable of performing disassembly:
largo% readelf -i 1 hello.o
0x00000000  pushl       %ebp
0x00000001  movl        %esp,%ebp
0x00000003  pushl       $0x0
0x00000008  call        0x08007559
0x0000000d  addl        $4,%esp
0x00000010  movl        %ebp,%esp
0x00000012  popl        %ebp
0x00000013  ret
The .rel.text section contains the relocations for the .text section of the file, and we can display them as follows:
largo% readelf -r hello.o
Relocation section data:.rel.text (0x2 entries)
Tag: 00004 Value 00301 R_386_32    (0 )
Tag: 00009 Value 00b02 R_386_PC32  (0 printf)
This indicates that the .text section has two relocations. As expected, there is a relocation for printf indicating that we must patch the address of printf into offset 9 from the beginning of the .text section, which happens to be the operand of the call instruction. There is also a relocation so that we pass the correct address to printf.
Now let us see what happens when this file is linked into an executable. The section table now looks something like Listing 2.
The first thing you will notice is a lot more sections than were in the simple .o file. Much of this because this file requires the ELF shared library libc.so.1.
At this point I should mention the mechanics of what happens when you run an ELF program. The kernel looks through the binary and loads it into the user's virtual memory. If the application is linked to a shared library, the application will also contain the name of the dynamic linker that should be used. The kernel then transfers control to the dynamic linker, not to the application. The dynamic loader is responsibile for first initializing itself, loading the shared libraries into memory, resolving all remaining relocations, and then transferring control to the application.
Going back to our executable, the .interp section simply contains an ASCII string that is the name of the dynamic loader. Currently this will always be /lib/elf/ld-linux.so.1 (the dynamic loader itself is also an ELF shared library).
Next you will notice 3 sections, called .hash, .dynsym, and .dynstr. This is a minimal symbol table used by the dynamic linker when performing relocations. You will notice that these sections are mapped into virtual memory (the virtual address field is non-zero). At the very end of the image are the regular symbol and string tables, and these are not mapped into virtual memory by the loader. The .hash section is just a hash table that is used so that we can quickly locate a given symbol in the .dynsym section, thereby avoiding a linear search of the symbol table. A given symbol can typically be located in one or two tries through the use of the hash table.
The next section I want to mention is the .plt section. This contains the jump table that is used when we call functions in the shared library. By default the .plt entries are all initialized by the linker not to point to the correct target functions, but instead to point to the dynamic loader itself. Thus, the first time you call any given function, the dynamic loader looks up the function and fixes the target of the .plt so that the next time this .plt slot is used we call the correct function. After making this change, the dynamic loader calls the function itself.
This feature is known as lazy symbol binding. The idea is that if you have lots of shared libraries, it could take the dynamic loader lots of time to look up all of the functions to initialize all of the .plt slots, so it would be preferable to defer binding addresses to the functions until we actually need them. This turns out to be a big win if you only end up using a small fraction of the functions in a shared library. It is possible to instruct the dynamic loader to bind addresses to all of the .plt slots before transferring control to the application—this is done by setting the environment variable LD_BIND_NOW=1 before running the program. This turns out to be useful in some cases when you are debugging a program, for example. Also, I should point out that the .plt is in read-only memory. Thus the addresses used for the target of the jump are actually stored in the .got section. The .got also contains a set of pointers for all of the global variables that are used within a program that come from a shared library.
The .dynamic section contains some shorthand notes used by the dynamic loader. You will notice that the section table is not itself loaded into virtual memory, and in fact it would not be good for performance for the dynamic loader to have to try to parse it to figure out what needs to be done. The .dynamic section is essentially just a distilled version of the section header table that contains just what is needed for the dynamic loader to do its job.
You will notice that since the section header table is not loaded into memory, neither the kernel nor the dynamic loader will be able to use that table when loading files into memory. A shorthand table of program headers is added to provide a distilled version of the section table containing just the information required to load a file into memory. For the above file it looks something like:
largo% readelf -l hello
Elf file is Executable
Entry point 0x8000400
There are 5 program headers, starting at offset 34:
PHDR       0x00034 0x08000034 0x000a0 0x000a0 R E
Interp     0x000d4 0x080000d4 0x00017 0x00017 R
Requesting program interpreter \
[/lib/elf/ld-linux.so.1]
Load       0x00000 0x08000000 0x00515 0x00515 R E
Load       0x00518 0x08001518 0x000cc 0x000d4 RW
Dynamic    0x0054c 0x0800154c 0x00098 0x00098 RW
Shared library: [libc.so.4] 1
As you can see, the program header contains a pointer to the name of the dynamic loader, instructions on what portions of the file are to be loaded into virtual memory (and the virtual addresses they should be loaded to), the permissions of the segments of memory, and finally a pointer to the .dynamic section that the dynamic loader will need. Note that the list of required shared libraries is stored in the .dynamic section.
I will not pick apart an ELF shared library for you here—libraries look quite similar to ELF executables. If you are interested, you can get the readelf utility and pick apart your own libraries.
At the start of this article, I said one reason we were switching to ELF was that it was easier to build shared libraries with ELF. I will now demonstrate how. Consider two files:
largo% cat hello1.c
main()
{
        greet();
}
largo% cat english.c
greet()
{
        printf("Hello World\n");
}
The idea is that we want to build a shared library from english.c, and link hello1 against it. The commands to generate the shared library are:
largo% gcc-elf -fPIC -c english.c
largo% gcc-elf -shared -o libenglish.so english.o
That's all there is to it. Now we compile and link the hello1 program:
largo% gcc-elf -c hello1.c
largo% gcc-elf -o hello1 hello1.o -L. -lenglish
And finally we can run the program. Normally the dynamic loader only looks in certain locations for shared libraries, and the current directory is not one of the places it normally looks. Thus to run the program, you can use a command like:
largo% LD_LIBRARY_PATH=. ./hello1
Hello World
The environment variable LD_LIBRARY_PATH tells the dynamic loader to look in additional places for the shared libraries (this feature is disabled for setuid programs for security reasons).
To avoid having to specify LD_LIBRARY_PATH, you have several options. You could copy your shared library to /lib/elf, but you can also link your program in the following way:
largo% gcc-elf -o hello1 hello1.o\ /home/joe/libenglish.so
largo% ./hello1
Hello World
To build more complicated shared libraries, the procedure is not really that much different. Everything that you want to put into the shared library should be compiled with -fPIC; when you have compiled everything, you just link it all together with thegcc -shared command.
The procedure is so much simpler mainly because we bind addresses to functions at runtime. With a.out libraries, the addresses are bound at link time. This means that lots of special care must be taken to ensure that the .plt and .got have sufficient room for future expansion and that we keep the variables at the same addresses from one version of the library to the next. The tools for building a.out libraries help ensure all of this, but it makes the build procedure much more complicated.
ELF offers one further feature that is not easily available with a.out. The dlopen()function can be used to dynamically load a shared library into the user's memory, and you are then able to call the dynamic loader to find symbols within this shared library—in other words, you can call functions that are defined in these modules. In addition, the dynamic loader is used to resolve any undefined symbols within the module itself.
This may be easiest to explain with an example. Given the following source file:
#include 
main(int argc, char * argv[])
{
   void (*greeting)();
   void * module;
   if( argc > 2 ) exit(0);
   module = dlopen(argv[1], RTLD_LAZY);
  if(!module) exit(0);
   greeting = dlsym(module, "greet");
   if(greeting) {
     (*greeting)();
   }
  dlclose(module);
 }
you can compile, link, and run it (using the shared library english.so which was built earlier):
largo% gcc-elf -c hello2.c
largo% gcc-elf -o hello2 hello2.o -ldl
largo% ./hello2 ./libenglish.so
Hello World
To expand this example a little bit, you could generate other modules with greetings in other languages. Thus in theory, one could add multi-lingual support for some application merely by supplying a set of shared libraries that contain the language-specific portions of the application. In the above example, I showed how you can locate the address of a function within a shared library. But the dlsym() function will also return the address of data variables, so you could just as easily retrieve the address of a text string from the shared library.
As I prepare to close, I should mention some options to readelf which I have not demonstrated. readelf -s dumps the symbol tables and readelf -f dumps the .dynamic section.
Finally, I should mention something about the timetable. When we first got ELF to a point where it was usable (last September), we decided to spend a relatively long period of time testing it and shaking out all of the problems. Back then I felt that roughly 4-to-6 months would allow people to test it thoroughly, plus we wanted to give an opportunity for certain applications to be adapted for ELF (the most recent versions of insmod and Wine now support ELF, for example). As I write this, no firm date has been set for a public release, but it is possible that ELF will be public by the time you read this.
In these articles I have attempted to give you a guided introduction to the ELF file format. A lot of the material I have covered is not of much practical value to most users (unless you want to hack the linker), but my experience is that there are a lot of people who are curious about how it all works, and I hope that I have provided enough information to satisfy most people.
For more information about the ELF file format, you can obtain the ELF specifications from a number of sources—you can try ftp.intel.com in pub/tis/elf11g.zip. The specifications are also available in a printed format. See SYSTEM V Application Binary Interface (ISBN 0-13-100439-5) and SYSTEM V Application Binary Interface, Intel386 Architecture Processor Supplement (ISBN 0-13-104670-5).
Eric Youngdale has worked with Linux for over three years, and has been active in kernel development. He developed the current a.out Linux shared libraries before developing much of the new ELF support. He can be reached as eric@aib.com.

'via Blog this'

Thursday, March 8, 2012

Sign extension & Zero extension

http://www.plantation-productions.com/Webster/www.artofasm.com/Windows/HTML/DataRepresentationa5.html#999653
3.10 Sign Extension, Zero Extension, Contraction, and Saturation
Since two's complement format integers have a fixed length, a small problem develops. What happens if you need to convert an eight bit two's complement value to 16 bits? This problem, and its converse (converting a 16 bit value to eight bits) can be accomplished via sign extension and contraction operations. Likewise, the 80x86 works with fixed length values, even when processing unsigned binary numbers. Zero extension lets you convert small unsigned values to larger unsigned values.
Consider the value "-64". The eight bit two's complement value for this number is $C0. The 16-bit equivalent of this number is $FFC0. Now consider the value "+64". The eight and 16 bit versions of this value are $40 and $0040, respectively. The difference between the eight and 16 bit numbers can be described by the rule: "If the number is negative, the H.O. byte of the 16 bit number contains $FF; if the number is positive, the H.O. byte of the 16 bit quantity is zero."
To sign extend a value from some number of bits to a greater number of bits is easy, just copy the sign bit into all the additional bits in the new format. For example, to sign extend an eight bit number to a 16 bit number, simply copy bit seven of the eight bit number into bits 8..15 of the 16 bit number. To sign extend a 16 bit number to a double word, simply copy bit 15 into bits 16..31 of the double word.
You must use sign extension when manipulating signed values of varying lengths. Often you'll need to add a byte quantity to a word quantity. You must sign extend the byte quantity to a word before the operation takes place. Other operations (multiplication and division, in particular) may require a sign extension to 32-bits. You must not sign extend unsigned values.
Sign Extension:
 
Eight Bits  Sixteen Bits  Thirty-two Bits
 

 
 $80        $FF80         $FFFF_FF80
 
 $28        $0028         $0000_0028
 
 $9A        $FF9A         $FFFF_FF9A
 
 $7F        $007F         $0000_007F
 
 ---        $1020         $0000_1020
 
 ---        $8086         $FFFF_8086
 

 
To extend an unsigned byte you must zero extend the value. Zero extension is very easy - just store a zero into the H.O. byte(s) of the larger operand. For example, to zero extend the value $82 to 16-bits you simply add a zero to the H.O. byte yielding $0082.
 
Zero Extension:
 
Eight Bits    Sixteen Bits           Thirty-two Bits
 

 
 $80            $0080                 $0000_0080
 
 $28            $0028                 $0000_0028
 
 $9A            $009A                 $0000_009A
 
 $7F            $007F                 $0000_007F
 
 ---            $1020                 $0000_1020
 
 ---            $8086                 $0000_8086
 

 
The 80x86 provides several instructions that will let you sign or zero extend a smaller number to a larger number. The first group of instructions we will look at will sign extend the AL, AX, or EAX register. These instructions are
  • cbw(); // Converts the byte in AL to a word in AX via sign extension.
  • cwd(); // Converts the word in AX to a double word in DX:AX
  • cdq(); // Converts the double word in EAX to the quad word in EDX:EAX
  • cwde(); // Converts the word in AX to a doubleword in EAX.
...

'via Blog this'