x86_64要注意的问题

原创 2011年01月21日 17:42:00

1 各种数据类型的长度

主要区别在long。long在32bit上是4bytes,在64bit上是8bytes。

 

2 指针类型

如果要强制转换,用long,不要用int。

 

3 x86_64上的汇编,参考这个,堆栈和参数传递与32bit上不同。http://www.x86-64.org/documentation/abi.pdf

还有要注意的是movl等,改成movq.

 

4 编译的时候,可以编译出32bit的库。用gcc/g++ -m32,连接时,用LD = ld -m elf_i386,${LD} -r -o target.o src.o -L... -l...

 

5 在x86_64上,从汇编语言编译obj文件,如果要产生-fPIC格式的,需要注意一些问题。call function,get var address时,需要   

  movq xbar@GOTPCREL(%rip), %rax

 

====================================================================================
 
= Position-Independent Code and Dynamic Linking =
 
We need to generate position-independent code on most platforms when we want our code to go into dynamic libraries (also referred to as shared libraries or DLLs). On some platforms (AIX, powerpc64-linux, x86_64-darwin), PIC is required for all code.
 
To access things defined in a dynamic library, we might need to do special things, such as look up the address of the imported thing in a table of pointers, depending on what platform we are on.
 
== How to access symbols ==
 
A C compiler is in an unfortunate position when generating PIC code, as it does not have any hints, whether an accessed symbol ends up in the same dynamic library or if it is truely an external symbol (from the dynamic library point of view). It can only generate non-PIC access for symbols generated within the same object file. In Haskell, we can do better as we assume all package code to end up in a single dynamic library. Hence, all intra-package symbol accesses can be generated as code that does direct access. For all inter-package accesses (package haskell98 accessing symbols in package base, e.g.), we have to generate PIC code. For the following we establish the following: 
 
 * ''object-local symbols'', symbols within the same object file. Always generate direct access. 
 * ''package-local symbols'', symbols within the same Haskell package. The NCG can generate direct access code, C compilers can't.
 * ''local symbols'', either object-local or package-local.
 * ''global symbols'', symbol in different libraries/packages. Always generate PIC.
 
== CLabel.labelDynamic ==
 
On most platforms, we can access any global symbol as if it was imported from a dynamic library; this usually means a small performance hit (an extra pointer dereference), but it is otherwise harmless. On some platforms, we have to access all global symbols this way. On Windows, we must know exactly which symbols are DLL-imported and which aren't.
 
Module `CLabel` contains a function `labelDynamic :: CLabel -> Bool` which is supposed to know whether a `CLabel` is imported from a dynamic library. On Windows, this function needs to be exact; everywhere else, we don't mind the occasional false positive.
 
== Info Tables ==
 
Info tables are in the text segment, which is supposed to be read-only and position-independent. Therefore, an info table ''must not'' contain any absolute address; instead, all addresses in info tables are instead encoded as relative offsets from the info label.
 
Note that this is done even when we are generating code that is otherwise position-dependent, in order to preserve binary compatibility between PIC and non-PIC.
 
It is not possible to generate those relative references from C code, so for the via-C compilation route, we pretty-print these relative references (`CmmLabelDiffOff` in cmm) as absolute references and have the mangler convert them to relative references again.
 
== Imported labels in SRTs (Windows) ==
 
Windows doesn't support references to imported labels in the data segment; on other platforms, the dynamic linker will just relocate the pointers in the SRTs to point to the right symbols. There is a hack in the code that tries to work around it; it might be bitrotted, and it might have been made unnecessary by the GNU linker's new auto-import on Windows.
 
== PIC and dynamic linking support in the NCG ==
 
The module `PositionIndependentCode` lies at the heart of PIC and dynamic linking support in the native code generator.
 
The basic idea is to call a function `cmmMakeDynamicReference` for all labels accessed from the code during the cmm-to-cmm transformation phase. This function will decide on the appropriate way to access the given label for the current platform and the current combination of -fPIC and -dynamic flags.
 
We extend Cmm and the `CLabel` module by a few things to allow us to express all the different things that occur on different platforms:
 
The `Cmm.GlobalReg` datatype has a constructor `PicBaseReg`. This PIC base register is the register relative to which position-independent references are calculated. This can be a general-purpose register that is allocated on a per-CmmProc basis, or it can be a dedicated register, like the instruction pointer `%rip` on x86_64.
 
== How things are done on different platforms ==
 
This section is a survey of how PIC and dynamic linking works on different platforms. There are small snippets of assembly code for several platforms, platforms that are similar to other platforms are left out (e.g. powerpc-darwin is left out, because the logic is the same as for i386-darwin). I hope the reader will not be too confused by irrelevant differences between the platforms, such as the fact that Darwin and Windows prefix all symbols with an underscore, and Linux doesn't.
 
=== Position dependent code ===
 
In the absence of PIC and dynamic linking, things are simple; when we use a label in assembly code, the linker will make sure it points to the right place.
 
{{{
# i386-linux without PIC and without dynamic linking
# i386-mingw32 and i386-darwin without dynamic linking
#         are the same with leading underscores.
# get the address of variable bar:
    movl $bar, %eax
# read a 4-byte-variable bar:
    movl bar, %eax
# call function foo:
    call foo
# tail-call foo_info:
    jmp foo_info
}}}
 
Now, to access a symbol `xfoo` that has been imported from a dynamic library, we do not want to mention the address of `xfoo` in the text section, because it would need to be modified at load-time.
 
One solution is to allocate a pointer to the imported symbol in a writable section and have the dynamic linker fill in this pointer table. The pointer table itself resides at a statically known address. The __imp__* symbols on Windows are automatically generated by the linker.
 
{{{
# i386-mingw32, accessing imported symbols
# get the address of imported symbol xbar:
    movl __imp__xbar, %eax
# read a 4-byte-variable xbar:
    movl __imp__xbar, %eax
    movl (%eax), %eax
# call imported function xfoo:
    call *__imp__xfoo
# tail-call imported xfoo_info:
    jmp *__imp__xfoo_info
}}}
 
On Mac OS X, the same system is used for data imports, but this time we have to define the symbol pointers ourselves. For references to code, there is an additional mechanism available; we can jump to a small piece of stub code that will resolve the symbol the first time it is used, in order to reduce application load times. Unfortunately, everything on Mac OS X requires 16-byte stack alignment, even the dynamic linker, so we cannot use this for a tail call.
 
{{{
# i386-darwin, accessing imported symbols
# get the address of imported symbol xbar:
    movl L_xbar$non_lazy_ptr, %eax
# read a 4-byte-variable xbar:
    movl L_xbar$non_lazy_ptr, %eax
    movl (%eax), %eax
# call imported function xfoo:
    call L_xfoo$stub
# tail-call imported xfoo_info:
    jmp *L_xfoo$non_lazy_ptr
 
# And now we need to define those L_*$* things:
 
    .section __IMPORT,__pointers,non_lazy_symbol_pointers
L_xbar$non_lazy_ptr:
    .indirect_symbol _xbar
    .long   0
L_xfoo$non_lazy_ptr:
    .indirect_symbol _xfoo
    .long   0
 
    .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_foo$stub:
    .indirect_symbol _foo
    hlt ; hlt ; hlt ; hlt ; hlt
    # The linker will insert a jmp instruction instead of those hlts
}}}
 
In theory, dynamic linking is transparent to position-dependent code on Linux, i.e. the code for accessing imported labels should look exactly the same as for non-imported labels. Unfortunately, things just don't work as they should for strange stuff like info tables.
 
When the ELF static linker finds a jump or call to an imported symbol, it automatically redirects the jump or call to a linker generated code stub (in the so-called procedure linkage table, or PLT). The linker then considers the label to be a code label and redirects all further references to the label to the code stub, even if they are data references. If this ever happens to an info label, our program will crash, as there is no info table in front of the code stub.
 
When the ELF static linker finds a data reference to an imported symbol (that it doesn't consider a code label), it allocates space for that symbol in the executable's data section and issues an `R_COPY` relocation, which instructs the dynamic linker to copy the (initial) contents of the symbol to its new place in the executable's image. All references to the symbol from the dynamic library are relocated to point to the symbol's new location, instead.
 
If `R_COPY` is ever used for an info label, our program will also crash, because the data we're interested in is *before* the info label and is not copied to the symbol's new home.
 
Fortunately, if the static linker finds a pointer to an imported symbol in a writable section, it just instructs the dynamic linker to update that pointer to the symbols address, without doing anything "funny". We can therefore work around these problems.
 
The workaround is inspired by the position-independent code that GCC generates for powerpc-linux, a platform that is amazingly broken.
 
{{{
# i386-linux, accessing imported symbols
# get the address of imported variable xbar:
    movl $xbar, %eax
# read a 4-byte-variable xbar:
    movl xbar, %eax
# call an imported function xfoo:
    call xfoo
    
# Up to here, everything was fine
# (assuming that xbar and xfoo are conventional variables and functions, 
#  as we would find them in foreign code)
# From here on, we have to use a workaround:
    
# tail-call imported xfoo_info:
    jmp *.LC_xfoo_info
# get the address of an imported info table xfoo_info:
    movl .LC_xfoo_info, %eax
    
.section ".got2", "aw"
.LC_xfoo_info:
    .long xfoo_info
}}}
 
Things look pretty much the same on x86_64-linux, powerpc-linux and powerpc-darwin; PowerPC has the added handicap that it takes two instructions to load a 32 bit quantity into a register. On x86_64-darwin, powerpc64-linux and all versions of AIX, PIC is ''required''.
 
=== Position independent code ===
 
First, let it be said that there is no such thing as position-independent code on Windows. The dynamic linker will just patiently relocate all dynamic libraries that are not loaded at their preferred base address. On all other platforms, PIC is at least strongly recommended for dynamic libraries.
 
In an ideal world, there would be assembler instructions for referring to things via an offset from the current instruction pointer. Jump instructions are ip-relative on all platforms that GHC runs on, but for data accesses, only x86_64 is this ideal world.
 
On x86_64, on both Linux and Mac OS X, we can use `foo(%rip)` to encode an instruction pointer relative data reference to `foo`, and `foo@GOTPCREL(%rip)` to encode an instruction pointer relative referece to a linker-generated symbol pointer for symbol `foo`.
A linker-generated code stub for imported code can be accessed by appending `@PLT` to the label on Linux, and is used implicitly when necessary on Mac OS X.
 
Again, we have to avoid the code stubs for tail-calls and use the symbol pointer instead, because there is a stack alignment requirement.
 
{{{
# x86_64-linux, -fPIC
# x86_64-darwin is almost the same,
#   .. but with leading underscores and no @PLT suffixes
 
# get the address of variable bar:
    leaq bar(%rip), %rax
# read a 4-byte-variable bar:
    movl bar(%rip), %eax
# call function foo:
    call foo
# tail-call foo_info:
    jmp foo_info
 
# get the address of imported symbol xbar:
    movq xbar@GOTPCREL(%rip), %rax
# read a 4-byte-variable xbar:
    movq xbar@GOTPCREL(%rip), %rax
    movl (%rax), %eax
# call imported function xfoo:
    call xfoo@PLT
# tail-call imported xfoo_info:
    jmp *xfoo_info@GOTPCREL(%rip)
}}}
 
 
Other platforms are not nearly as nice; i386 and powerpc[64] do not have a way of accessing the current instruction pointer or referring to data relative to it. The *only* way to get at the current instruction pointer is to issue a call instruction. To generate PIC code, we have to do just that at the beginning of each function.
 
On Darwin, things are relatively straightforward:
{{{
# i386-darwin, -fPIC
    
# first, initialise PIC:
    call    1f
1:  pop     %ebx
    # now, %ebx contains the address of local label 1
    # (Note: local label 1 is referred to as "1f" before its definition,
    #        and as "1b" after its definition)
 
# get the address of variable bar:
    leal _bar-1b(%ebx), %eax
# read a 4-byte-variable bar:
    movl _bar-1b(%ebx), %eax
# call function foo:
    call foo
# tail-call foo_info:
    jmp foo_info
 
# get the address of imported symbol xbar:
    movl L_xbar$non_lazy_ptr-1b(%ebx), %eax
# read a 4-byte-variable xbar:
    movl L_xbar$non_lazy_ptr-1b(%ebx), %eax
    movl (%eax), %eax
# call imported function xfoo:
    call L_xfoo$stub
# tail-call imported xfoo_info:
    jmp *L_xfoo$non_lazy_ptr-1b(%ebx)
 
# And now we need to define those L_*$* things:
 
    .section __IMPORT,__pointers,non_lazy_symbol_pointers
L_xbar$non_lazy_ptr:
    .indirect_symbol _xbar
    .long   0
L_xfoo$non_lazy_ptr:
    .indirect_symbol _xfoo
    .long   0
 
    .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5
L_foo$stub:
    .indirect_symbol _foo
    hlt ; hlt ; hlt ; hlt ; hlt
    # The linker will insert a jmp instruction instead of those hlts
}}}
 
There is one more small additional complication on Darwin. The assembler doesn't support label difference expressions involving labels not defined in the same source file, so we have to treat all symbols not defined in the same source file as dynamically imported.
 
 
On Linux, we need to first calculate the address of the Global Offset Table (GOT) and then use `bar@GOT` to refer to symbol pointers and `bar@GOTOFF` to refer to a local symbol relative to the GOT.
Also, the linker-generated code-stubs (`xfoo@PLT`) require the address of the GOT to be in register `%ebx` when they are invoked. The NCG currently doesn't do this, so we avoid code stubs altogether on i386.
 
{{{
# i386-linux, -fPIC
    
# first, initialise PIC:
    call    1f
1:  pop     %ebx
    # now, %ebx contains the address of local label 1
    addl    $_GLOBAL_OFFSET_TABLE_+(.-1b), %ebx
    # now, %ebx contains the address of the GOT
 
# get the address of variable bar:
    leal bar@GOTOFF(%ebx), %eax
# read a 4-byte-variable bar:
    movl bar@GOTOFF(%ebx), %eax
# call function foo:
    call foo
# tail-call foo_info:
    jmp foo_info
 
# get the address of imported symbol xbar:
    movl xbar@GOT(%ebx), %eax
# read a 4-byte-variable xbar:
    movl xbar@GOT(%ebx), %eax
    movl (%eax), %eax
# call imported function xfoo:
        
    # using the PLT would work here, because we happened to use %ebx,
    # but the NCG won't do it right now:
    # call xfoo@PLT
    
    # Instead, we use the symbol pointer:
    call *xfoo@GOT(%ebx)
 
# tail-call imported xfoo_info:
    jmp *xfoo@GOT(%ebx)
}}}
 
'''To be done:''' powerpc-linux, AIX/powerpc64-linux
 
== Linking on ELF ==
 
To generate a DSO on ELF platform, we use GNU ld. Except for `-Bsymbolic`, ld is invoked regularly with the `-shared` option, and `-o` pointing to the output DSO file followed objects that in its sum compose an entire package. In Haskell, we assume that there is a one-to-one mapping from packages to DSOs. So, all parts of the base package will end up in a libHSbase.so. As intra-package references are not generated as PIC code, we have to supply all objects that make up a package, so that ld is able to resolve these references before writing a (.text) relocation free DSO library file. To enable these cross-object relocations GNU ld needs `-Bsymbolic`.
 
== Mangling dynamic library names ==
 
As Haskell DSOs might end up in standard library paths, and as they might not be compatible among compilers and compiler version, we need to mangle their names to include the compiler and its version.
 
The scheme is libHS''<package>''-''<package-version>''-''<compiler><compilerversion>''.so. E.g. libHSbase-2.1-ghc6.6.so

 

==================================================================================

音响系统电源和线路故障解决方案

内容提要:音响系统电源和线路故障解决方案,一、音响系统电源故障,(1)、系统总电源故障:音响系统总的电源配置很重要,需要注意的有以下几点:   一、音响系统电源故障   (1)、系统总电源故障...
  • axl19530209
  • axl19530209
  • 2015年01月07日 08:51
  • 503

AsyncTask注意事项

昨天看《Android开发艺术探索》的时候,对AsyncTask中的几个点比较感兴趣: 先贴源码注释截图 1、AsyncTask不适合特别耗时的任务      AsyncTask...
  • u013933272
  • u013933272
  • 2016年03月30日 10:07
  • 376

[数据库]关于设计表时应该注意的问题

如有错误欢迎大家指出。这段时间在家里,做了点修正。 1、慎重选择表名。 有两种选择: 按照多数开发语言的命名规则。比如(myCustomer)。 按照多数开源思想命名规则。比如(my_cust...
  • SunnyYoona
  • SunnyYoona
  • 2014年05月19日 10:25
  • 1467

iOS开发~制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a

一、概要 平时项目开发中,可能使用第三方提供的静态库.a,如果.a提供方技术不成熟,使用的时候就会出现问题,例如: 在真机上编译报错:No architectures to compile for...
  • zfpp25_
  • zfpp25_
  • 2015年01月04日 13:21
  • 22222

android SQLite要注意的问题

SQL语句的拼接问题: 我们使用数据库的可视化的管理工具中使用SQL语句可以很方便的操作数据库,但是如果我们原封不动的把这些语句搬到android中,我们会发现这样是行不通的。 如果我们使...
  • u010715440
  • u010715440
  • 2015年03月07日 11:24
  • 361

用C++进行跨平台和可移植开发的注意事项

概述   今天聊聊C++的可移植性问题。如果你平时使用C++进行开发,并且你对C++的可移植性问题不是非常清楚,那么我建议你看看这个系列。即使你目前没有跨平台开发的需要,了解可移植性方面的知识对你还...
  • bzhxuexi
  • bzhxuexi
  • 2014年06月26日 14:46
  • 1427

CSS及HTML 常见误区和注意事项(一)

CSS及HTML 常见误区和注意事项(一)为什么要设置HTML和body的高度
  • qq_25684647
  • qq_25684647
  • 2017年03月15日 21:21
  • 170

手机app测试的注意事项

以下是功能测试时需要注意的点: 登录   ●登录用户名和密码错误时,界面有提示信息   ●用户主动退出登录后,下次启动APP时,应该进入登录界面   ●对于支持自动登录的APP,数据交换时 ...
  • changNet
  • changNet
  • 2017年07月19日 12:04
  • 356

关于串口复用造成的意外及总结

前两天测试人员发现,在测试运行的产品中,有两个运行不正常。于是对出现异常的产品进行了重点检测。 开始怀疑是产品中的无线模块信号不好,造成一段时间后就连接断掉。于是使用了一个测试好用的无线模块,测试发...
  • tietao
  • tietao
  • 2014年03月15日 10:04
  • 2203

在Hibernate中,使用二级缓存机制要注意什么?

Hibernate中使用二级缓存时要注意的几点如下: 二级缓存能够明显提高系统的性能,当然,如果数据量特别巨大,此时不适合于二级缓存,原因是缓存的数据量过大可能会引起内存资源紧张,反而降低性能。 对于...
  • qwdafedv
  • qwdafedv
  • 2015年07月21日 13:10
  • 548
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:x86_64要注意的问题
举报原因:
原因补充:

(最多只允许输入30个字)